home *** CD-ROM | disk | FTP | other *** search
/ Aminet 28 / Aminet 28 (1998)(GTI - Schatztruhe)[!][Dec 1998].iso / Aminet / dev / c / qtools0.2-src.lha / src / libqtools / ILBM.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-07-18  |  82.0 KB  |  3,012 lines

  1. #define    LIBQTOOLS_CORE
  2. #include "../include/libqtools.h"
  3.  
  4. /* ilbmtoppm.c - read an IFF ILBM file and produce a portable pixmap
  5.  *
  6.  * Copyright (C) 1989 by Jef Poskanzer.
  7.  *
  8.  * Permission to use, copy, modify, and distribute this software and its
  9.  * documentation for any purpose and without fee is hereby granted, provided
  10.  * that the above copyright notice appear in all copies and that both that
  11.  * copyright notice and this permission notice appear in supporting
  12.  * documentation.  This software is provided "as is" without express or
  13.  * implied warranty.
  14.  *
  15.  * Modified by Mark Thompson on 10/4/90 to accomodate 24 bit IFF files
  16.  * as used by ASDG, NewTek, etc.
  17.  *
  18.  * Modified by Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de)
  19.  *  20/Jun/93:
  20.  *  - row-by-row operation
  21.  *  - better de-interleave algorithm
  22.  *  - colormap files
  23.  *  - direct color
  24.  *  04/Oct/93:
  25.  *  - multipalette support (PCHG chunk)
  26.  *  - options -ignore, -isham, -isehb and -adjustcolors
  27.  */
  28.  
  29. /* prototypes */
  30. static void getfourchars ARGS((FILE * f, char fourchars[4]));
  31. static unsigned char get_byte ARGS((FILE * f));
  32. static long get_big_long ARGS((FILE * f));
  33. static short get_big_short ARGS((FILE * f));
  34. static void readerr ARGS((FILE * f));
  35.  
  36. static void skip_chunk ARGS((FILE * f, long chunksize));
  37. static void display_chunk ARGS((FILE * ifp, char *iffid, long chunksize));
  38. static pixel *read_colormap ARGS((FILE * f, long colors));
  39. static BitMapHeader *read_bmhd ARGS((FILE * f));
  40. static PCHGInfo *read_pchg ARGS((FILE * ifp, unsigned long chunksize));
  41.  
  42. static void ham_to_ppm ARGS((FILE * ifp, BitMapHeader * bmhd, pixel * colormap, int colors, PCHGInfo * pchginfo));
  43. static void deep_to_ppm ARGS((FILE * ifp, BitMapHeader * bmhd));
  44. static void cmap_to_ppm ARGS((pixel * colormap, int colors));
  45. static void std_to_ppm ARGS((FILE * ifp, BitMapHeader * bmhd, pixel * colormap, int colors, PCHGInfo * pchginfo, long viewportmodes));
  46. static void direct_to_ppm ARGS((FILE * ifp, BitMapHeader * bmhd, DirectColor * dcol));
  47.  
  48. static void init_pchg ARGS((PCHGInfo * pchginfo, pixel * colormap, int colors, pixval newmaxval));
  49. static void adjust_colormap ARGS((PCHGInfo * pchginfo, int row));
  50. static void scale_colormap ARGS((pixel * colormap, int colors, pixval oldmaxval, pixval newmaxval));
  51. static pixel *ehb_to_cmap ARGS((pixel * colormap, int *colors));
  52. static void read_ilbm_plane ARGS((FILE * ifp, int cols, int compression));
  53. static void decode_row ARGS((FILE * ifp, rawtype * chunkyrow, int planes, BitMapHeader * bmhd));
  54.  
  55. static rawtype *alloc_rawrow ARGS((int cols));
  56. static void *xmalloc ARGS((int bytes));
  57.  
  58. #define MALLOC(n, type)     (type *)tmalloc((n) * sizeof(type))
  59.  
  60. static short verbose = 0;
  61. static short adjustcolors = 0;
  62. static unsigned char *ilbmrow;
  63. static pixel *pixelrow;
  64.  
  65. struct rawpic *LoadILBM(HANDLE ilbmFile, int flags, int ignore)
  66. {
  67.   FILE *ifp;
  68.   pixel *colormap = 0;
  69.   int argn, colors;
  70.   char iffid[5];
  71.   short body = 0;
  72.   long formsize, bytesread, chunksize, viewportmodes = 0, fakeviewport = 0;
  73.   char *usage = "[-verbose] [-ignore <chunkID>] [-isham|-isehb] [-adjustcolors] [ilbmfile]";
  74.   BitMapHeader *bmhd = NULL;
  75.   DirectColor *dcol = NULL;
  76.   PCHGInfo *pchginfo = NULL;
  77.  
  78. #define MAX_IGNORE  16
  79.   char *ignorelist[MAX_IGNORE];
  80.   int ignorecount = 0;
  81.  
  82.   ppm_init(&argc, argv);
  83.  
  84.   argn = 1;
  85.   while (argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0') {
  86.     if (pm_keymatch(argv[argn], "-verbose", 2))
  87.       verbose = 1;
  88.     else if (pm_keymatch(argv[argn], "-noverbose", 4))
  89.       verbose = 0;
  90.     else if (pm_keymatch(argv[argn], "-isham", 4))
  91.       fakeviewport |= vmHAM;
  92.     else if (pm_keymatch(argv[argn], "-isehb", 4))
  93.       fakeviewport |= vmEXTRA_HALFBRITE;
  94.     else if (pm_keymatch(argv[argn], "-adjustcolors", 2))
  95.       adjustcolors = 1;
  96.     else if (pm_keymatch(argv[argn], "-noadjustcolors", 4))
  97.       adjustcolors = 0;
  98.     else if (pm_keymatch(argv[argn], "-ignore", 2)) {
  99.       if (++argn >= argc)
  100.     pm_usage(usage);
  101.       if (strlen(argv[argn]) != 4)
  102.     pm_error("\"-ignore\" option needs a 4 byte chunk ID string as argument");
  103.       if (ignorecount >= MAX_IGNORE)
  104.     pm_error("max %d chunk IDs to ignore", MAX_IGNORE);
  105.       ignorelist[ignorecount++] = argv[argn];
  106.     }
  107.     else
  108.       pm_usage(usage);
  109.     ++argn;
  110.   }
  111.  
  112.   if (argn < argc) {
  113.     ifp = pm_openr(argv[argn]);
  114.     argn++;
  115.   }
  116.   else
  117.     ifp = stdin;
  118.  
  119.   if (argn != argc)
  120.     pm_usage(usage);
  121.  
  122.   /* Read in the ILBM file. */
  123.   iffid[4] = '\0';
  124.   getfourchars(ifp, iffid);
  125.   if (strcmp(iffid, "FORM") != 0)
  126.     pm_error("input is not a FORM type IFF file");
  127.   formsize = get_big_long(ifp);
  128.   getfourchars(ifp, iffid);
  129.   if (strcmp(iffid, "ILBM") != 0)
  130.     pm_error("input is not an ILBM type FORM IFF file");
  131.   bytesread = 4;                        /* FORM and formsize do not count */
  132.  
  133.   /* Main loop, parsing the IFF FORM. */
  134.   while (bytesread < formsize) {
  135.     short i, ignore = 0;
  136.  
  137.     getfourchars(ifp, iffid);
  138.     chunksize = get_big_long(ifp);
  139.     bytesread += 8;
  140.  
  141.     for (i = 0; i < ignorecount && !ignore; i++) {
  142.       if (strcmp(ignorelist[i], iffid) == 0)
  143.     ignore = 1;
  144.     }
  145.  
  146.     if (ignore) {
  147.       ignore = 0;
  148.       pm_message("ignoring \"%s\" chunk", iffid);
  149.       skip_chunk(ifp, chunksize);
  150.     }
  151.     else if (body != 0) {
  152.       pm_message("\"%s\" chunk found after BODY chunk - skipping", iffid);
  153.       skip_chunk(ifp, chunksize);
  154.     }
  155.     else if (strcmp(iffid, "BMHD") == 0) {
  156.       if (chunksize != BitMapHeaderSize)
  157.     pm_error("BMHD chunk size mismatch");
  158.       bmhd = read_bmhd(ifp);
  159.     }
  160.     else if (strcmp(iffid, "CMAP") == 0) {
  161.       colors = chunksize / 3;
  162.       if (colors == 0) {
  163.     pm_error("warning - empty colormap");
  164.     skip_chunk(ifp, chunksize);
  165.       }
  166.       else {
  167.     long r = 3 * colors;
  168.  
  169.     colormap = read_colormap(ifp, colors);
  170.     while (r++ < chunksize)
  171.       (void)get_byte(ifp);
  172.       }
  173.     }
  174.     else if (strcmp(iffid, "CAMG") == 0) {
  175.       if (chunksize != CAMGChunkSize)
  176.     pm_error("CAMG chunk size mismatch");
  177.       viewportmodes = get_big_long(ifp);
  178.     }
  179.     else if (strcmp(iffid, "DCOL") == 0) {
  180.       if (chunksize != DirectColorSize)
  181.     pm_error("DCOL chunk size mismatch");
  182.       dcol = MALLOC(1, DirectColor);
  183.       dcol->r = get_byte(ifp);
  184.       dcol->g = get_byte(ifp);
  185.       dcol->b = get_byte(ifp);
  186.       (void)get_byte(ifp);
  187.     }
  188.     else if (strcmp(iffid, "PCHG") == 0) {
  189.       pchginfo = read_pchg(ifp, chunksize);
  190.     }
  191.     else if (strcmp(iffid, "BODY") == 0) {
  192.       if (bmhd == NULL)
  193.     pm_error("\"BODY\" chunk without \"BMHD\" chunk");
  194.  
  195.       ilbmrow = MALLOC(RowBytes(bmhd->w), unsigned char);
  196.  
  197.       pixelrow = ppm_allocrow(bmhd->w);
  198.  
  199.       viewportmodes |= fakeviewport;
  200.  
  201.       if (viewportmodes & vmHAM)
  202.     ham_to_ppm(ifp, bmhd, colormap, colors, pchginfo);
  203.       else if (dcol != NULL)
  204.     direct_to_ppm(ifp, bmhd, dcol);
  205.       else if (bmhd->nPlanes == 24)
  206.     deep_to_ppm(ifp, bmhd);
  207.       else
  208.     std_to_ppm(ifp, bmhd, colormap, colors, pchginfo, viewportmodes);
  209.       body = 1;
  210.     }
  211.     else if (strcmp(iffid, "GRAB") == 0 || strcmp(iffid, "DEST") == 0 ||
  212.          strcmp(iffid, "SPRT") == 0 || strcmp(iffid, "CRNG") == 0 ||
  213.          strcmp(iffid, "CCRT") == 0 || strcmp(iffid, "CLUT") == 0 ||
  214.          strcmp(iffid, "DPPV") == 0 || strcmp(iffid, "DRNG") == 0 ||
  215.          strcmp(iffid, "EPSF") == 0) {
  216.       skip_chunk(ifp, chunksize);
  217.     }
  218.     else if (strcmp(iffid, "(c) ") == 0 || strcmp(iffid, "AUTH") == 0 ||
  219.          strcmp(iffid, "NAME") == 0 || strcmp(iffid, "ANNO") == 0 ||
  220.          strcmp(iffid, "TEXT") == 0) {
  221.       if (verbose)
  222.     display_chunk(ifp, iffid, chunksize);
  223.       else
  224.     skip_chunk(ifp, chunksize);
  225.     }
  226.     else if (strcmp(iffid, "DPI ") == 0) {
  227.       int x, y;
  228.  
  229.       x = get_big_short(ifp);
  230.       y = get_big_short(ifp);
  231.       if (verbose)
  232.     pm_message("\"DPI \" chunk:  dpi_x = %d    dpi_y = %d", x, y);
  233.     }
  234.     else {
  235.       pm_message("unknown chunk type \"%s\" - skipping", iffid);
  236.       skip_chunk(ifp, chunksize);
  237.     }
  238.  
  239.     bytesread += chunksize;
  240.     if (odd(chunksize)) {
  241.       (void)get_byte(ifp);
  242.       ++bytesread;
  243.     }
  244.   }
  245.   pm_close(ifp);
  246.  
  247.   if (body == 0) {
  248.     if (colormap)
  249.       cmap_to_ppm(colormap, colors);
  250.     else
  251.       pm_error("no \"BODY\" or \"CMAP\" chunk found");
  252.   }
  253.  
  254.   if (bytesread != formsize) {
  255.     pm_message("warning - file length (%ld bytes) does not match FORM size field (%ld bytes) +8",
  256.            bytesread, formsize);
  257.   }
  258.  
  259.   exit(0);
  260. }
  261.  
  262. static void readerr(f)
  263.     FILE *f;
  264. {
  265.   if (ferror(f))
  266.     pm_error("read error");
  267.   else
  268.     pm_error("premature EOF");
  269. }
  270.  
  271. static unsigned char get_byte(ifp)
  272.     FILE *ifp;
  273. {
  274.   int i;
  275.  
  276.   i = getc(ifp);
  277.   if (i == EOF)
  278.     readerr(ifp);
  279.  
  280.   return (unsigned char)i;
  281. }
  282.  
  283. static void getfourchars(ifp, fourchars)
  284.     FILE *ifp;
  285.     char fourchars[4];
  286. {
  287.   fourchars[0] = get_byte(ifp);
  288.   fourchars[1] = get_byte(ifp);
  289.   fourchars[2] = get_byte(ifp);
  290.   fourchars[3] = get_byte(ifp);
  291. }
  292.  
  293. static long get_big_long(ifp)
  294.     FILE *ifp;
  295. {
  296.   long l;
  297.  
  298.   if (pm_readbiglong(ifp, &l) == -1)
  299.     readerr(ifp);
  300.  
  301.   return l;
  302. }
  303.  
  304. static short get_big_short(ifp)
  305.     FILE *ifp;
  306. {
  307.   short s;
  308.  
  309.   if (pm_readbigshort(ifp, &s) == -1)
  310.     readerr(ifp);
  311.  
  312.   return s;
  313. }
  314.  
  315. static void skip_chunk(ifp, chunksize)
  316.     FILE *ifp;
  317.     long chunksize;
  318. {
  319.   int i;
  320.  
  321.   for (i = 0; i < chunksize; i++)
  322.     (void)get_byte(ifp);
  323. }
  324.  
  325. static pixel *
  326.   read_colormap(ifp, colors)
  327.     FILE *ifp;
  328.     long colors;
  329. {
  330.   pixel *colormap;
  331.   int i, r, g, b;
  332.   pixval colmaxval = 0;
  333.  
  334.   colormap = ppm_allocrow(colors);
  335.   for (i = 0; i < colors; i++) {
  336.     r = get_byte(ifp);
  337.     if (r > colmaxval)
  338.       colmaxval = r;
  339.     g = get_byte(ifp);
  340.     if (g > colmaxval)
  341.       colmaxval = g;
  342.     b = get_byte(ifp);
  343.     if (b > colmaxval)
  344.       colmaxval = b;
  345.     PPM_ASSIGN(colormap[i], r, g, b);
  346.   }
  347. #ifdef DEBUG
  348.   pm_message("colormap maxval is %d", colmaxval);
  349. #endif
  350.   if (colmaxval == 0)
  351.     pm_message("warning - black colormap");
  352.   else if (colmaxval <= 15) {
  353.     if (!adjustcolors) {
  354.       pm_message("warning - probably 4 bit colormap");
  355.       pm_message("use \"-adjustcolors\" to scale colormap to 8 bits");
  356.     }
  357.     else {
  358.       pm_message("scaling colormap to 8 bits");
  359.       scale_colormap(colormap, colors, 15, MAXCOLVAL);
  360.     }
  361.   }
  362.   return colormap;
  363. }
  364.  
  365. static BitMapHeader *
  366.   read_bmhd(ifp)
  367.     FILE *ifp;
  368. {
  369.   BitMapHeader *bmhd;
  370.  
  371.   bmhd = MALLOC(1, BitMapHeader);
  372.  
  373.   bmhd->w = get_big_short(ifp);                    /* cols */
  374.   bmhd->h = get_big_short(ifp);                    /* rows */
  375.   bmhd->x = get_big_short(ifp);
  376.   bmhd->y = get_big_short(ifp);
  377.   bmhd->nPlanes = get_byte(ifp);
  378.   bmhd->masking = get_byte(ifp);
  379.   bmhd->compression = get_byte(ifp);
  380.   bmhd->pad1 = get_byte(ifp);                    /* (ignored) */
  381.   bmhd->transparentColor = get_big_short(ifp);
  382.   bmhd->xAspect = get_byte(ifp);
  383.   bmhd->yAspect = get_byte(ifp);
  384.   bmhd->pageWidth = get_big_short(ifp);
  385.   bmhd->pageHeight = get_big_short(ifp);
  386.  
  387.   if (verbose) {
  388.     pm_message("dimensions: %dx%d", bmhd->w, bmhd->h);
  389.     pm_message("BODY compression: %s", bmhd->compression <= cmpMAXKNOWN ?
  390.            cmpNAME[bmhd->compression] : "unknown");
  391.   }
  392.  
  393.   /* fix aspect ratio */
  394.   if (bmhd->xAspect == 0) {
  395.     if (bmhd->yAspect == 0) {
  396.       pm_message("warning - xAspect:yAspect = 0:0, using 1:1");
  397.       bmhd->xAspect = bmhd->yAspect = 1;
  398.     }
  399.     else {
  400.       pm_message("warning - xAspect = 0, setting to yAspect");
  401.       bmhd->xAspect = bmhd->yAspect;
  402.     }
  403.   }
  404.   else {
  405.     if (bmhd->yAspect == 0) {
  406.       pm_message("warning - yAspect = 0, setting to xAspect");
  407.       bmhd->yAspect = bmhd->xAspect;
  408.     }
  409.   }
  410.   if (bmhd->xAspect != bmhd->yAspect) {
  411.     pm_message("warning - non-square pixels; to fix do a 'pnmscale -%cscale %g'",
  412.            bmhd->xAspect > bmhd->yAspect ? 'x' : 'y',
  413.            bmhd->xAspect > bmhd->yAspect ? (float)(bmhd->xAspect) / bmhd->yAspect : (float)(bmhd->yAspect) / bmhd->xAspect);
  414.   }
  415.  
  416.   return bmhd;
  417. }
  418.  
  419. static void ham_to_ppm(ifp, bmhd, colormap, colors, pchginfo)
  420.     FILE *ifp;
  421.     BitMapHeader *bmhd;
  422.     pixel *colormap;
  423.     int colors;
  424.     PCHGInfo *pchginfo;
  425. {
  426.   int cols, rows, hambits, hammask, col, row;
  427.   pixval maxval;
  428.   rawtype *rawrow;
  429.   int pchgflag = (pchginfo && colormap);
  430.  
  431.   cols = bmhd->w;
  432.   rows = bmhd->h;
  433.   hambits = bmhd->nPlanes - 2;
  434.   hammask = (1 << hambits) - 1;
  435.  
  436.   pm_message("input is a %sHAM%d file", pchgflag ? "multipalette " : "", bmhd->nPlanes);
  437.  
  438.   if (hambits > MAXPLANES)
  439.     pm_error("too many planes (max %d)", MAXPLANES);
  440.   if (hambits < 0) {
  441.     pm_message("HAM requires 2 or more planes");
  442.     pm_error("try \"-ignore CAMG\" to treat this file as a normal ILBM");
  443.   }
  444.  
  445.   maxval = pm_bitstomaxval(hambits);
  446.   if (maxval > PPM_MAXMAXVAL)
  447.     pm_error("nPlanes is too large - try reconfiguring with PGM_BIGGRAYS\n    or without PPM_PACKCOLORS");
  448.  
  449.   /* scale colormap to new maxval */
  450.   if (colormap && maxval != MAXCOLVAL)
  451.     scale_colormap(colormap, colors, MAXCOLVAL, maxval);
  452.  
  453.   if (pchgflag)
  454.     init_pchg(pchginfo, colormap, colors, maxval);
  455.  
  456.   rawrow = alloc_rawrow(cols);
  457.  
  458.   ppm_writeppminit(stdout, cols, rows, maxval, 0);
  459.   for (row = 0; row < rows; row++) {
  460.     pixval r, g, b;
  461.  
  462.     if (pchgflag)
  463.       adjust_colormap(pchginfo, row);
  464.  
  465.     decode_row(ifp, rawrow, bmhd->nPlanes, bmhd);
  466.  
  467.     r = g = b = 0;
  468.     for (col = 0; col < cols; col++) {
  469.       switch ((rawrow[col] >> hambits) & 0x03) {
  470.     case HAMCODE_CMAP:
  471.       if (colormap && colors >= maxval)
  472.         pixelrow[col] = colormap[rawrow[col] & hammask];
  473.       else
  474.         PPM_ASSIGN(pixelrow[col], rawrow[col] & hammask,
  475.                rawrow[col] & hammask, rawrow[col] & hammask);
  476.       r = PPM_GETR(pixelrow[col]);
  477.       g = PPM_GETG(pixelrow[col]);
  478.       b = PPM_GETB(pixelrow[col]);
  479.       break;
  480.     case HAMCODE_BLUE:
  481.       b = rawrow[col] & hammask;
  482.       PPM_ASSIGN(pixelrow[col], r, g, b);
  483.       break;
  484.     case HAMCODE_RED:
  485.       r = rawrow[col] & hammask;
  486.       PPM_ASSIGN(pixelrow[col], r, g, b);
  487.       break;
  488.     case HAMCODE_GREEN:
  489.       g = rawrow[col] & hammask;
  490.       PPM_ASSIGN(pixelrow[col], r, g, b);
  491.       break;
  492.     default:
  493.       pm_error("impossible HAM code");
  494.       }
  495.     }
  496.     ppm_writeppmrow(stdout, pixelrow, cols, (pixval) maxval, 0);
  497.   }
  498. }
  499.  
  500. static void deep_to_ppm(ifp, bmhd)
  501.     FILE *ifp;
  502.     BitMapHeader *bmhd;
  503. {
  504.   int cols, rows, col, row;
  505.   rawtype *Rrow, *Grow, *Brow;
  506.  
  507.   cols = bmhd->w;
  508.   rows = bmhd->h;
  509.  
  510.   pm_message("input is a deep (24bit) ILBM");
  511.  
  512.   Rrow = alloc_rawrow(cols);
  513.   Grow = alloc_rawrow(cols);
  514.   Brow = alloc_rawrow(cols);
  515.  
  516.   ppm_writeppminit(stdout, cols, rows, MAXCOLVAL, 0);
  517.   for (row = 0; row < rows; row++) {
  518.     decode_row(ifp, Rrow, 8, bmhd);
  519.     decode_row(ifp, Grow, 8, bmhd);
  520.     decode_row(ifp, Brow, 8, bmhd);
  521.     for (col = 0; col < cols; col++)
  522.       PPM_ASSIGN(pixelrow[col], Rrow[col], Grow[col], Brow[col]);
  523.     ppm_writeppmrow(stdout, pixelrow, cols, MAXCOLVAL, 0);
  524.   }
  525.   pm_close(stdout);
  526. }
  527.  
  528. static void direct_to_ppm(ifp, bmhd, dcol)
  529.     FILE *ifp;
  530.     BitMapHeader *bmhd;
  531.     DirectColor *dcol;
  532. {
  533.   int cols, rows, col, row, redplanes, greenplanes, blueplanes;
  534.   rawtype *Rrow, *Grow, *Brow;
  535.   pixval maxval, redmaxval, greenmaxval, bluemaxval;
  536.   int scale;
  537.  
  538.   cols = bmhd->w;
  539.   rows = bmhd->h;
  540.  
  541.   redplanes = dcol->r;
  542.   greenplanes = dcol->g;
  543.   blueplanes = dcol->b;
  544.  
  545.   pm_message("input is a %d:%d:%d direct color ILBM",
  546.          redplanes, greenplanes, blueplanes);
  547.  
  548.   if (redplanes > MAXPLANES || blueplanes > MAXPLANES || greenplanes > MAXPLANES)
  549.     pm_error("too many planes (max %d per color)", MAXPLANES);
  550.  
  551.   if (bmhd->nPlanes != (redplanes + greenplanes + blueplanes))
  552.     pm_error("BMHD/DCOL plane number mismatch");
  553.  
  554.   if (redplanes == blueplanes && redplanes == greenplanes) {
  555.     scale = 0;
  556.     maxval = pm_bitstomaxval(redplanes);
  557.   }
  558.   else {
  559.     scale = 1;
  560.     redmaxval = pm_bitstomaxval(redplanes);
  561.     greenmaxval = pm_bitstomaxval(greenplanes);
  562.     bluemaxval = pm_bitstomaxval(blueplanes);
  563.  
  564.     maxval = max(redmaxval, max(greenmaxval, bluemaxval));
  565.     pm_message("rescaling colors to %d bits", pm_maxvaltobits(maxval));
  566.   }
  567.  
  568.   if (maxval > PPM_MAXMAXVAL)
  569.     pm_error("too many planes - try reconfiguring with PGM_BIGGRAYS\n    or without PPM_PACKCOLORS");
  570.  
  571.   Rrow = alloc_rawrow(cols);
  572.   Grow = alloc_rawrow(cols);
  573.   Brow = alloc_rawrow(cols);
  574.  
  575.   ppm_writeppminit(stdout, cols, rows, maxval, 0);
  576.   for (row = 0; row < rows; row++) {
  577.     decode_row(ifp, Rrow, dcol->r, bmhd);
  578.     decode_row(ifp, Grow, dcol->g, bmhd);
  579.     decode_row(ifp, Brow, dcol->b, bmhd);
  580.  
  581.     if (scale) {
  582.       for (col = 0; col < cols; col++) {
  583.     PPM_ASSIGN(pixelrow[col],
  584.            Rrow[col] * maxval / redmaxval,
  585.            Grow[col] * maxval / greenmaxval,
  586.            Brow[col] * maxval / bluemaxval);
  587.       }
  588.     }
  589.     else {
  590.       for (col = 0; col < cols; col++)
  591.     PPM_ASSIGN(pixelrow[col], Rrow[col], Grow[col], Brow[col]);
  592.     }
  593.     ppm_writeppmrow(stdout, pixelrow, cols, maxval, 0);
  594.   }
  595.   pm_close(stdout);
  596. }
  597.  
  598. static void cmap_to_ppm(colormap, colors)
  599.     pixel *colormap;
  600.     int colors;
  601. {
  602.   pm_message("input is a colormap file");
  603.  
  604.   ppm_writeppminit(stdout, colors, 1, MAXCOLVAL, 0);
  605.   ppm_writeppmrow(stdout, colormap, colors, MAXCOLVAL, 0);
  606.   pm_close(stdout);
  607. }
  608.  
  609. static void std_to_ppm(ifp, bmhd, colormap, colors, pchginfo, viewportmodes)
  610.     FILE *ifp;
  611.     BitMapHeader *bmhd;
  612.     pixel *colormap;
  613.     int colors;
  614.     PCHGInfo *pchginfo;
  615.     long viewportmodes;
  616. {
  617.   rawtype *rawrow;
  618.   pixval maxval;
  619.   int row, rows, col, cols;
  620.   int pchgflag = (pchginfo && colormap);
  621.  
  622.   cols = bmhd->w;
  623.   rows = bmhd->h;
  624.  
  625.   pm_message("input is a %d-plane %s%sILBM", bmhd->nPlanes,
  626.          pchgflag ? "multipalette " : "",
  627.          viewportmodes & vmEXTRA_HALFBRITE ? "EHB " : ""
  628.     );
  629.  
  630.   if (bmhd->nPlanes > MAXPLANES)
  631.     pm_error("too many planes (max %d)", MAXPLANES);
  632.  
  633.   if (colormap)
  634.     maxval = MAXCOLVAL;
  635.   else {
  636.     maxval = pm_bitstomaxval(bmhd->nPlanes);
  637.     pm_message("no colormap - interpreting values as grayscale");
  638.   }
  639.   if (maxval > PPM_MAXMAXVAL)
  640.     pm_error("nPlanes is too large - try reconfiguring with PGM_BIGGRAYS\n    or without PPM_PACKCOLORS");
  641.  
  642.   if (pchgflag)
  643.     init_pchg(pchginfo, colormap, colors, maxval);
  644.  
  645.   rawrow = alloc_rawrow(cols);
  646.  
  647.   if (viewportmodes & vmEXTRA_HALFBRITE)
  648.     colormap = ehb_to_cmap(colormap, &colors);
  649.  
  650.   ppm_writeppminit(stdout, cols, rows, (pixval) maxval, 0);
  651.   for (row = 0; row < rows; row++) {
  652.  
  653.     if (pchgflag)
  654.       adjust_colormap(pchginfo, row);
  655.  
  656.     decode_row(ifp, rawrow, bmhd->nPlanes, bmhd);
  657.     for (col = 0; col < cols; col++) {
  658.       if (colormap)
  659.     pixelrow[col] = colormap[rawrow[col]];
  660.       else
  661.     PPM_ASSIGN(pixelrow[col], rawrow[col], rawrow[col], rawrow[col]);
  662.     }
  663.     ppm_writeppmrow(stdout, pixelrow, cols, maxval, 0);
  664.   }
  665. }
  666.  
  667. static pixel *
  668.   ehb_to_cmap(colormap, colors)
  669.     pixel *colormap;
  670.     int *colors;
  671. {
  672.   pixel *tempcolormap = NULL;
  673.   int i, col;
  674.  
  675.   if (colormap) {
  676.     col = *colors;
  677.     tempcolormap = ppm_allocrow(col * 2);
  678.     for (i = 0; i < col; i++) {
  679.       tempcolormap[i] = colormap[i];
  680.       PPM_ASSIGN(tempcolormap[col + i], PPM_GETR(colormap[i]) / 2,
  681.          PPM_GETG(colormap[i]) / 2, PPM_GETB(colormap[i]) / 2);
  682.     }
  683.     ppm_freerow(colormap);
  684.     *colors *= 2;
  685.   }
  686.   return tempcolormap;
  687. }
  688.  
  689. static void read_ilbm_plane(ifp, cols, compression)
  690.     FILE *ifp;
  691.     int cols, compression;
  692. {
  693.   unsigned char *ubp;
  694.   int bytes, j, byte;
  695.  
  696.   bytes = RowBytes(cols);
  697.  
  698.   switch (compression) {
  699.     case cmpNone:
  700.       j = fread(ilbmrow, 1, bytes, ifp);
  701.       if (j != bytes)
  702.     readerr(ifp);
  703.       break;
  704.     case cmpByteRun1:
  705.       ubp = ilbmrow;
  706.       do {
  707.     byte = (int)get_byte(ifp);
  708.     if (byte <= 127) {
  709.       j = byte;
  710.       bytes -= (j + 1);
  711.       if (bytes < 0)
  712.         pm_error("error doing ByteRun1 decompression");
  713.       for (; j >= 0; j--)
  714.         *ubp++ = get_byte(ifp);
  715.     }
  716.     else if (byte != 128) {
  717.       j = 256 - byte;
  718.       bytes -= (j + 1);
  719.       if (bytes < 0)
  720.         pm_error("error doing ByteRun1 decompression");
  721.       byte = (int)get_byte(ifp);
  722.       for (; j >= 0; j--)
  723.         *ubp++ = (unsigned char)byte;
  724.     }
  725.     /* 128 is a NOP */
  726.       }
  727.       while (bytes > 0);
  728.       break;
  729.     default:
  730.       pm_error("unknown compression type");
  731.   }
  732. }
  733.  
  734. const unsigned char bit_mask[] =
  735. {1, 2, 4, 8, 16, 32, 64, 128};
  736.  
  737. static void decode_row(ifp, chunkyrow, nPlanes, bmhd)
  738.     FILE *ifp;
  739.     rawtype *chunkyrow;
  740.     int nPlanes;
  741.     BitMapHeader *bmhd;
  742. {
  743.   int plane, col, cols;
  744.   unsigned char *ilp;
  745.   rawtype *chp;
  746.  
  747.   cols = bmhd->w;
  748.   for (plane = 0; plane < nPlanes; plane++) {
  749.     int mask, cbit;
  750.  
  751.     mask = 1 << plane;
  752.     read_ilbm_plane(ifp, cols, bmhd->compression);
  753.  
  754.     ilp = ilbmrow;
  755.     chp = chunkyrow;
  756.  
  757.     cbit = 7;
  758.     for (col = 0; col < cols; col++, cbit--, chp++) {
  759.       if (cbit < 0) {
  760.     cbit = 7;
  761.     ilp++;
  762.       }
  763.       if (*ilp & bit_mask[cbit])
  764.     *chp |= mask;
  765.       else
  766.     *chp &= ~mask;
  767.     }
  768.   }
  769.   /* skip mask plane */
  770.   if (bmhd->masking == mskHasMask)
  771.     read_ilbm_plane(ifp, cols, bmhd->compression);
  772. }
  773.  
  774. static rawtype *
  775.   alloc_rawrow(cols)
  776.     int cols;
  777. {
  778.   rawtype *r;
  779.   int i;
  780.  
  781.   r = MALLOC(cols, rawtype);
  782.  
  783.   for (i = 0; i < cols; i++)
  784.     r[i] = 0;
  785.  
  786.   return r;
  787. }
  788.  
  789. static void *
  790.   xmalloc(bytes)
  791.     int bytes;
  792. {
  793.   void *mem;
  794.  
  795.   if (bytes == 0)
  796.     return NULL;
  797.  
  798.   mem = malloc(bytes);
  799.   if (mem == NULL)
  800.     pm_error("out of memory allocating %d bytes", bytes);
  801.   return mem;
  802. }
  803.  
  804. static void display_chunk(ifp, iffid, chunksize)
  805.     FILE *ifp;
  806.     char *iffid;
  807.     long chunksize;
  808. {
  809.   int byte;
  810.  
  811.   pm_message("contents of \"%s\" chunk:", iffid);
  812.  
  813.   while (chunksize--) {
  814.     byte = get_byte(ifp);
  815.     if (fputc(byte, stderr) == EOF)
  816.       pm_error("write error");
  817.   }
  818.   if (fputc('\n', stderr) == EOF)
  819.     pm_error("write error");
  820. }
  821.  
  822. /*
  823.  * PCHG stuff
  824.  */
  825.  
  826. static void PCHG_Decompress ARGS((PCHGHeader * PCHG, PCHGCompHeader * CompHdr, unsigned char *compdata, unsigned long compsize, unsigned char *comptree, unsigned char *data));
  827. static unsigned char *PCHG_MakeMask ARGS((PCHGHeader * PCHG, unsigned char *data, unsigned long datasize, unsigned char **newdata));
  828. static void PCHG_ConvertSmall ARGS((PCHGInfo * Info, unsigned char *data, unsigned long datasize));
  829. static void PCHG_ConvertBig ARGS((PCHGInfo * Info, unsigned char *data, unsigned long datasize));
  830. static void PCHG_DecompHuff ARGS((unsigned char *src, unsigned char *dest, short *tree, unsigned long origsize));
  831. static void pchgerr ARGS((char *when));
  832.  
  833. /* Turn big-endian 4-byte long and 2-byte short stored at x (unsigned char *)
  834.  * into the native format of the CPU
  835.  */
  836. #define BIG_LONG(x) (   ((unsigned long)((x)[0]) << 24) + \
  837.                         ((unsigned long)((x)[1]) << 16) + \
  838.                         ((unsigned long)((x)[2]) <<  8) + \
  839.                         ((unsigned long)((x)[3]) <<  0) )
  840. #define BIG_WORD(x) (   ((unsigned short)((x)[0]) << 8) + \
  841.                         ((unsigned short)((x)[1]) << 0) )
  842.  
  843. static PCHGInfo *
  844.   read_pchg(ifp, bytesleft)
  845.     FILE *ifp;
  846.     unsigned long bytesleft;
  847. {
  848.   static PCHGInfo Info;
  849.   PCHGCompHeader CompHdr;
  850.   PCHGHeader *PCHG;
  851.   unsigned char *data, *chdata;
  852.   unsigned long datasize;
  853.  
  854. #ifdef DEBUG
  855.   pm_message("PCHG chunk found");
  856. #endif
  857.  
  858.   if (bytesleft < PCHGHeaderSize)
  859.     pchgerr("while reading PCHGHeader");
  860.  
  861.   Info.PCHG = PCHG = MALLOC(1, PCHGHeader);
  862.   PCHG->Compression = get_big_short(ifp);
  863.   PCHG->Flags = get_big_short(ifp);
  864.   PCHG->StartLine = get_big_short(ifp);
  865.   PCHG->LineCount = get_big_short(ifp);
  866.   PCHG->ChangedLines = get_big_short(ifp);
  867.   PCHG->MinReg = get_big_short(ifp);
  868.   PCHG->MaxReg = get_big_short(ifp);
  869.   PCHG->MaxChanges = get_big_short(ifp);
  870.   PCHG->TotalChanges = get_big_long(ifp);
  871.   bytesleft -= PCHGHeaderSize;
  872.  
  873. #ifdef DEBUG
  874.   pm_message("PCHG StartLine   : %d", PCHG->StartLine);
  875.   pm_message("PCHG LineCount   : %d", PCHG->LineCount);
  876.   pm_message("PCHG ChangedLines: %d", PCHG->ChangedLines);
  877.   pm_message("PCHG TotalChanges: %d", PCHG->TotalChanges);
  878. #endif
  879.  
  880.   if (PCHG->Compression != PCHG_COMP_NONE) {
  881.     unsigned char *compdata, *comptree;
  882.     unsigned long treesize;
  883.  
  884.     if (bytesleft < PCHGCompHeaderSize)
  885.       pchgerr("while reading PCHGCompHeader");
  886.  
  887.     CompHdr.CompInfoSize = get_big_long(ifp);
  888.     CompHdr.OriginalDataSize = get_big_long(ifp);
  889.     bytesleft -= PCHGCompHeaderSize;
  890.     treesize = CompHdr.CompInfoSize;
  891.     datasize = CompHdr.OriginalDataSize;
  892.  
  893.     if (bytesleft < treesize)
  894.       pchgerr("while reading compression info data");
  895.  
  896.     comptree = MALLOC(treesize, unsigned char);
  897.  
  898.     if (fread(comptree, 1, treesize, ifp) != treesize)
  899.       readerr(ifp);
  900.  
  901.     bytesleft -= treesize;
  902.     if (bytesleft == 0)
  903.       pchgerr("while reading compressed change structure data");
  904.  
  905.     compdata = MALLOC(bytesleft, unsigned char);
  906.     data = MALLOC(datasize, unsigned char);
  907.  
  908.     if (fread(compdata, 1, bytesleft, ifp) != bytesleft)
  909.       readerr(ifp);
  910.  
  911.     PCHG_Decompress(PCHG, &CompHdr, compdata, bytesleft, comptree, data);
  912.     free(comptree);
  913.     free(compdata);
  914.     bytesleft = 0;
  915.   }
  916.   else {
  917. #ifdef DEBUG
  918.     pm_message("uncompressed PCHG");
  919. #endif
  920.     if (bytesleft == 0)
  921.       pchgerr("while reading uncompressed change structure data");
  922.  
  923.     datasize = bytesleft;
  924.     data = MALLOC(datasize, unsigned char);
  925.  
  926.     if (fread(data, 1, datasize, ifp) != datasize)
  927.       readerr(ifp);
  928.     bytesleft = 0;
  929.   }
  930.  
  931.   Info.LineMask = PCHG_MakeMask(PCHG, data, datasize, &chdata);
  932.   datasize -= (chdata - data);
  933.  
  934.   Info.Palette = MALLOC(PCHG->TotalChanges, PaletteChange);
  935.   Info.Change = MALLOC(PCHG->ChangedLines, LineChanges);
  936.  
  937.   if (PCHG->Flags & PCHGF_USE_ALPHA)
  938.     pm_message("warning - PCHG alpha channel not supported");
  939.  
  940.   if (PCHG->Flags & PCHGF_12BIT) {
  941. #ifdef DEBUG
  942.     pm_message("SmallLineChanges");
  943. #endif
  944.     PCHG_ConvertSmall(&Info, chdata, datasize);
  945.   }
  946.   else if (PCHG->Flags & PCHGF_32BIT) {
  947. #ifdef DEBUG
  948.     pm_message("BigLineChanges");
  949. #endif
  950.     PCHG_ConvertBig(&Info, chdata, datasize);
  951.   }
  952.   else
  953.     pm_error("unknown palette changes structure format in PCHG chunk");
  954.  
  955.   free(data);
  956.   return &Info;
  957. }
  958.  
  959. static void PCHG_Decompress(PCHG, CompHdr, compdata, compsize, comptree, data)
  960.     PCHGHeader *PCHG;
  961.     PCHGCompHeader *CompHdr;
  962.     unsigned char *compdata;
  963.     unsigned long compsize;
  964.     unsigned char *comptree;
  965.     unsigned char *data;
  966. {
  967.   short *hufftree;
  968.   unsigned long huffsize, i;
  969.   unsigned long treesize = CompHdr->CompInfoSize;
  970.  
  971.   switch (PCHG->Compression) {
  972.     case PCHG_COMP_HUFFMAN:
  973.  
  974. #ifdef DEBUG
  975.       pm_message("PCHG Huffman compression");
  976. #endif
  977.       /* turn big-endian 2-byte shorts into native format */
  978.       huffsize = treesize / 2;
  979.       hufftree = MALLOC(huffsize, short);
  980.  
  981.       for (i = 0; i < huffsize; i++) {
  982.     hufftree[i] = (short)BIG_WORD(comptree);
  983.     comptree += 2;
  984.       }
  985.  
  986.       /* decompress the change structure data */
  987.       PCHG_DecompHuff(compdata, data, &hufftree[huffsize - 1], CompHdr->OriginalDataSize);
  988.  
  989.       free(hufftree);
  990.       break;
  991.     default:
  992.       pm_error("unknown PCHG compression type");
  993.   }
  994. }
  995.  
  996. static unsigned char *
  997.   PCHG_MakeMask(PCHG, data, datasize, newdata)
  998.     PCHGHeader *PCHG;
  999.     unsigned char *data;
  1000.     unsigned long datasize;
  1001.     unsigned char **newdata;
  1002. {
  1003.   unsigned long bytes;
  1004.   unsigned char *mask;
  1005.  
  1006.   /* the mask at 'data' is in 4-byte big-endian longword format,
  1007.    * thus we can simply treat it at unsigned char and don't have
  1008.    * to convert it, just copy it to a new mem block so we can
  1009.    * free the original data
  1010.    */
  1011.   bytes = MaskLongWords(PCHG->LineCount) * 4;
  1012.   if (datasize < bytes)
  1013.     pchgerr("for line mask");
  1014.   mask = MALLOC(bytes, unsigned char);
  1015.  
  1016. #ifdef DEBUG
  1017.   pm_message("%ld bytes for line mask", bytes);
  1018. #endif
  1019.   bcopy(data, mask, bytes);
  1020.  
  1021.   *newdata = (data + bytes);
  1022.   return mask;
  1023. }
  1024.  
  1025. static void PCHG_ConvertSmall(Info, data, datasize)
  1026.     PCHGInfo *Info;
  1027.     unsigned char *data;
  1028.     unsigned long datasize;
  1029. {
  1030.   PCHGHeader *PCHG = Info->PCHG;
  1031.   LineChanges *Change = Info->Change;
  1032.   PaletteChange *Palette = Info->Palette;
  1033.   unsigned long i, palettecount = 0;
  1034.   unsigned char ChangeCount16, ChangeCount32;
  1035.   unsigned short SmallChange;
  1036.  
  1037.   Info->maxval = 15;                        /* 4 bit values */
  1038.  
  1039.   for (i = 0; i < PCHG->ChangedLines; i++) {
  1040.     int n;
  1041.  
  1042.     if (datasize < 2)
  1043.       goto fail;
  1044.     ChangeCount16 = *data++;
  1045.     ChangeCount32 = *data++;
  1046.     datasize -= 2;
  1047.  
  1048.     Change[i].Count = ChangeCount16 + ChangeCount32;
  1049.     Change[i].Palette = &Palette[palettecount];
  1050.  
  1051.     for (n = 0; n < Change[i].Count; n++) {
  1052.       if (palettecount >= PCHG->TotalChanges)
  1053.     goto fail;
  1054.       if (datasize < 2)
  1055.     goto fail;
  1056.       SmallChange = BIG_WORD(data);
  1057.       data += 2;
  1058.       datasize -= 2;
  1059.  
  1060.       Palette[palettecount].Register = (SmallChange >> 12) & 0x0f;
  1061.       if (n >= ChangeCount16)
  1062.     Palette[palettecount].Register += 16;
  1063.       Palette[palettecount].Alpha = 0;
  1064.       Palette[palettecount].Red = (SmallChange >> 8) & 0x0f;
  1065.       Palette[palettecount].Green = (SmallChange >> 4) & 0x0f;
  1066.       Palette[palettecount].Blue = SmallChange & 0x0f;
  1067.       palettecount++;
  1068.     }
  1069.   }
  1070. #ifdef DEBUG
  1071.   pm_message("%ld palette change structures", palettecount);
  1072. #endif
  1073.   return;
  1074. fail:
  1075.   pchgerr("while building SmallLineChanges array");
  1076. }
  1077.  
  1078. static void PCHG_ConvertBig(Info, data, datasize)
  1079.     PCHGInfo *Info;
  1080.     unsigned char *data;
  1081.     unsigned long datasize;
  1082. {
  1083.   PCHGHeader *PCHG = Info->PCHG;
  1084.   LineChanges *Change = Info->Change;
  1085.   PaletteChange *Palette = Info->Palette;
  1086.   unsigned long i, palettecount = 0;
  1087.  
  1088.   Info->maxval = MAXCOLVAL;
  1089.  
  1090.   for (i = 0; i < PCHG->ChangedLines; i++) {
  1091.     int n;
  1092.  
  1093.     if (datasize < 2)
  1094.       goto fail;
  1095.     Change[i].Count = BIG_WORD(data);
  1096.     data += 2;
  1097.     datasize -= 2;
  1098.  
  1099.     Change[i].Palette = &Palette[palettecount];
  1100.  
  1101.     for (n = 0; n < Change[i].Count; n++) {
  1102.       if (palettecount >= PCHG->TotalChanges)
  1103.     goto fail;
  1104.       if (datasize < 6)
  1105.     goto fail;
  1106.       Palette[palettecount].Register = BIG_WORD(data);
  1107.       data += 2;
  1108.       Palette[palettecount].Alpha = *data++;
  1109.       Palette[palettecount].Red = *data++;
  1110.       Palette[palettecount].Blue = *data++;            /* yes, RBG */
  1111.       Palette[palettecount].Green = *data++;
  1112.       palettecount++;
  1113.       datasize -= 6;
  1114.     }
  1115.   }
  1116. #ifdef DEBUG
  1117.   pm_message("%ld palette change structures", palettecount);
  1118. #endif
  1119.   return;
  1120. fail:
  1121.   pchgerr("while building BigLineChanges array");
  1122. }
  1123.  
  1124. static void pchgerr(when)
  1125.     char *when;
  1126. {
  1127.   pm_message("insufficient data in PCHG chunk %s", when);
  1128.   pm_error("try the \"-ignore\" option to skip this chunk");
  1129. }
  1130.  
  1131. static void PCHG_DecompHuff(src, dest, tree, origsize)
  1132.     unsigned char *src, *dest;
  1133.     short *tree;
  1134.     unsigned long origsize;
  1135. {
  1136.   unsigned long i = 0, bits = 0;
  1137.   unsigned char thisbyte;
  1138.   short *p;
  1139.  
  1140.   p = tree;
  1141.   while (i < origsize) {
  1142.     if (bits == 0) {
  1143.       thisbyte = *src++;
  1144.       bits = 8;
  1145.     }
  1146.     if (thisbyte & (1 << 7)) {
  1147.       if (*p >= 0) {
  1148.     *dest++ = (unsigned char)*p;
  1149.     i++;
  1150.     p = tree;
  1151.       }
  1152.       else
  1153.     p += (*p / 2);
  1154.     }
  1155.     else {
  1156.       p--;
  1157.       if (*p > 0 && (*p & 0x100)) {
  1158.     *dest++ = (unsigned char)*p;
  1159.     i++;
  1160.     p = tree;
  1161.       }
  1162.     }
  1163.     thisbyte <<= 1;
  1164.     bits--;
  1165.   }
  1166. }
  1167.  
  1168. static void init_pchg(pchginfo, colormap, colors, newmaxval)
  1169.     PCHGInfo *pchginfo;
  1170.     pixel *colormap;
  1171.     int colors;
  1172.     pixval newmaxval;
  1173. {
  1174.   PCHGHeader *PCHG = pchginfo->PCHG;
  1175.   pixval oldmaxval = pchginfo->maxval;
  1176.   int row;
  1177.  
  1178.   pchginfo->colormap = colormap;
  1179.   pchginfo->colors = colors;
  1180.  
  1181.   if (oldmaxval != newmaxval) {
  1182.     PaletteChange *Palette = pchginfo->Palette;
  1183.     unsigned long i;
  1184.  
  1185. #ifdef DEBUG
  1186.     pm_message("scaling PCHG palette from %d to %d", oldmaxval, newmaxval);
  1187. #endif
  1188.  
  1189.     for (i = 0; i < PCHG->TotalChanges; i++) {
  1190.       Palette[i].Red = Palette[i].Red * newmaxval / oldmaxval;
  1191.       Palette[i].Green = Palette[i].Green * newmaxval / oldmaxval;
  1192.       Palette[i].Blue = Palette[i].Blue * newmaxval / oldmaxval;
  1193.     }
  1194.     pchginfo->maxval = newmaxval;
  1195.   }
  1196.  
  1197.   for (row = PCHG->StartLine; row < 0; row++)
  1198.     adjust_colormap(pchginfo, row);
  1199. }
  1200.  
  1201. static void adjust_colormap(pchginfo, row)
  1202.     PCHGInfo *pchginfo;
  1203.     int row;
  1204. {
  1205.   static unsigned long maskcount, changecount;
  1206.   static unsigned char thismask;
  1207.   static int bits;
  1208.  
  1209.   PCHGHeader *PCHG = pchginfo->PCHG;
  1210.  
  1211.   if (row < PCHG->StartLine || changecount >= PCHG->ChangedLines)
  1212.     return;
  1213.  
  1214.   if (bits == 0) {
  1215.     thismask = pchginfo->LineMask[maskcount++];
  1216.     bits = 8;
  1217.   }
  1218.  
  1219.   if (thismask & (1 << 7)) {
  1220.     int i;
  1221.  
  1222.     for (i = 0; i < pchginfo->Change[changecount].Count; i++) {
  1223.       PaletteChange *pal = &(pchginfo->Change[changecount].Palette[i]);
  1224.       int reg = pal->Register;
  1225.  
  1226.       if (reg >= pchginfo->colors) {
  1227.     pm_message("warning - PCHG palette change register value out of range");
  1228.     pm_message("    row %d  change structure %ld  palette %d", row, changecount, i);
  1229.     pm_message("    ignoring it... colors might get messed up from here");
  1230.       }
  1231.       else
  1232.     PPM_ASSIGN(pchginfo->colormap[reg], pal->Red, pal->Green, pal->Blue);
  1233.     }
  1234.     changecount++;
  1235.   }
  1236.   thismask <<= 1;
  1237.   bits--;
  1238. }
  1239.  
  1240. static void scale_colormap(colormap, colors, oldmaxval, newmaxval)
  1241.     pixel *colormap;
  1242.     int colors;
  1243.     pixval oldmaxval, newmaxval;
  1244. {
  1245.   int i, r, g, b;
  1246.  
  1247.   for (i = 0; i < colors; i++) {
  1248.     r = PPM_GETR(colormap[i]) * newmaxval / oldmaxval;
  1249.     g = PPM_GETG(colormap[i]) * newmaxval / oldmaxval;
  1250.     b = PPM_GETB(colormap[i]) * newmaxval / oldmaxval;
  1251.     PPM_ASSIGN(colormap[i], r, g, b);
  1252.   }
  1253. }
  1254.  
  1255. /* ppmtoilbm.c - read a portable pixmap and produce an IFF ILBM file
  1256.  *
  1257.  * Copyright (C) 1989 by Jef Poskanzer.
  1258.  * Modified by Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de)
  1259.  *  20/Jun/93:
  1260.  *  - 24bit support (new options -24if, -24force)
  1261.  *  - HAM8 support (well, anything from HAM3 to HAM(MAXPLANES))
  1262.  *  - now writes up to 8 (16) planes (new options -maxplanes, -fixplanes)
  1263.  *  - colormap file (new option -map)
  1264.  *  - write colormap only (new option -cmaponly)
  1265.  *  - only writes CAMG chunk if it is a HAM-picture
  1266.  *  29/Aug/93:
  1267.  *  - operates row-by-row whenever possible
  1268.  *  - faster colorscaling with lookup-table (~20% faster on HAM pictures)
  1269.  *  - options -ham8 and -ham6 now imply -hamforce
  1270.  *  27/Nov/93:
  1271.  *  - byterun1 compression (this is now default) with new options:
  1272.  *    -compress, -nocompress, -cmethod, -savemem
  1273.  *  - floyd-steinberg error diffusion (for std+mapfile and HAM)
  1274.  *  - new options: -lace and -hires --> write CAMG chunk
  1275.  *  - LUT for luminance calculation (used by ppm_to_ham)
  1276.  *
  1277.  *
  1278.  *           std   HAM  24bit cmap  direct
  1279.  *  -------+-----+-----+-----+-----+-----
  1280.  *  BMHD     yes   yes   yes   yes   yes
  1281.  *  CMAP     yes   (1)   no    yes   no
  1282.  *  BODY     yes   yes   yes   no    yes
  1283.  *  CAMG     (2)   yes   (2)   no    (2)
  1284.  *  other    -     -     -     -     DCOL
  1285.  *  nPlanes  1-8   3-8   24    0     3-24   if configured without ILBM_BIGRAW
  1286.  *  nPlanes  1-16  3-16  24    0     3-48   if configured with ILBM_BIGRAW
  1287.  *
  1288.  *  (1): grayscale colormap
  1289.  *  (2): only if "-lace" or "-hires" option used
  1290.  *
  1291.  * Permission to use, copy, modify, and distribute this software and its
  1292.  * documentation for any purpose and without fee is hereby granted, provided
  1293.  * that the above copyright notice appear in all copies and that both that
  1294.  * copyright notice and this permission notice appear in supporting
  1295.  * documentation.  This software is provided "as is" without express or
  1296.  * implied warranty.
  1297.  */
  1298.  
  1299. #define MODE_DIRECT     4                    /* direct color ILBM */
  1300. #define MODE_CMAP       3                    /* write normal file, but colormap only */
  1301. #define MODE_24         2                    /* write a 24bit (deep) ILBM */
  1302. #define MODE_HAM        1                    /* write a HAM */
  1303. #define MODE_NONE       0                    /* write a normal picture */
  1304.  
  1305. #define DEF_MAXPLANES   8
  1306. #define DEF_HAMPLANES   8
  1307. #define DEF_DCOLPLANES  5
  1308. #define DEF_COMPRESSION cmpByteRun1
  1309.  
  1310. typedef struct {
  1311.   int len;
  1312.   unsigned char *row;
  1313. } bodyrow;
  1314.  
  1315. typedef struct {
  1316.   long *thisrederr, *thisgreenerr, *thisblueerr;
  1317.   long *nextrederr, *nextgreenerr, *nextblueerr;
  1318.   int lefttoright;                        /* 1 for left-to-right scan, 0 for right-to-left */
  1319.   int cols;
  1320.   pixel *pixrow;
  1321.   pixval maxval;
  1322.   int col, col_end;
  1323.   int alternate;
  1324.   pixval red, green, blue;                    /* values of current pixel */
  1325. } floydinfo;
  1326.  
  1327. static int colorstobpp ARGS((int colors));
  1328.  
  1329. #define put_fourchars(str)  (void)(fputs(str, stdout))
  1330. static void put_big_short ARGS((short s));
  1331. static void put_big_long ARGS((long l));
  1332.  
  1333. #define put_byte(b)     (void)(putc((unsigned char)(b), stdout))
  1334. static void ppm_to_ham ARGS((FILE * fp, int cols, int rows, int maxval, int hambits, int nocolor));
  1335. static void ppm_to_24 ARGS((FILE * fp, int cols, int rows, int maxval));
  1336. static void ppm_to_direct ARGS((FILE * fp, int cols, int rows, int maxval, DirectColor * direct));
  1337. static void ppm_to_std ARGS((FILE * fp, int cols, int rows, int maxval, colorhist_vector chv, int colors, int nPlanes));
  1338. static void ppm_to_cmap ARGS((int maxval, colorhist_vector chv, int colors));
  1339. static void write_form_ilbm ARGS((int size));
  1340. static void write_bmhd ARGS((int cols, int rows, int nPlanes));
  1341. static void write_std_cmap ARGS((colorhist_vector chv, int colors, int maxval));
  1342. static int encode_row ARGS((FILE * outfile, rawtype * rawrow, int cols, int nPlanes));
  1343. static int compress_row ARGS((int bytes));
  1344. static int runbyte1 ARGS((int bytes));
  1345. static pixel *next_pixrow ARGS((FILE * fp, int row));
  1346. static pixval *make_val_table ARGS((pixval oldmaxval, pixval newmaxval));
  1347. static void *xmalloc ARGS((int bytes));
  1348.  
  1349. #define MALLOC(n, type)     (type *)tmalloc((n) * sizeof(type))
  1350. static void init_read ARGS((FILE * fp, int *colsP, int *rowsP, pixval * maxvalP, int *formatP, int readall));
  1351. static void write_body ARGS((void));
  1352. static void write_camg ARGS((void));
  1353. static void alloc_body_array ARGS((int rows, int nPlanes));
  1354. static void free_body_array ARGS((void));
  1355.  
  1356. #define PAD(n)      odd(n)                    /* pad to a word */
  1357. static int closest_color ARGS((colorhist_vector chv, int colors, pixval cmaxval, pixel * pP));
  1358. static floydinfo *init_floyd ARGS((int cols, pixval maxval, int alternate));
  1359. static void free_floyd ARGS((floydinfo * fi));
  1360. static void begin_floyd_row ARGS((floydinfo * fi, pixel * prow));
  1361. static pixel *next_floyd_pixel ARGS((floydinfo * fi));
  1362. static void update_floyd_pixel ARGS((floydinfo * fi, int r, int g, int b));
  1363. static void end_floyd_row ARGS((floydinfo * fi));
  1364.  
  1365. /* global data */
  1366. static unsigned char *coded_rowbuf;                /* buffer for uncompressed scanline */
  1367. static unsigned char *compr_rowbuf;                /* buffer for compressed scanline */
  1368. static pixel **pixels;                        /* PPM image (NULL for row-by-row operation) */
  1369. static pixel *pixrow;                        /* current row in PPM image (pointer into pixels array, or buffer for row-by-row operation) */
  1370. static bodyrow *ilbm_body = NULL;                /* compressed ILBM BODY */
  1371.  
  1372. static long viewportmodes = 0;
  1373. static int compr_type = DEF_COMPRESSION;
  1374.  
  1375. /* flags */
  1376. static short savemem = 0;                    /* slow operation, but uses less memory */
  1377. static short compr_force = 0;                    /* force compressed output, even if the image got larger  - NOT USED */
  1378. static short floyd = 0;                        /* apply floyd-steinberg error diffusion */
  1379.  
  1380. #define WORSTCOMPR(bytes)       ((bytes) + (bytes)/128 + 1)
  1381. #define DO_COMPRESS             (compr_type != cmpNone)
  1382. #define CAMGSIZE                (viewportmodes == 0 ? 0 : (4 + 4 + CAMGChunkSize))
  1383.  
  1384. /* Lookup tables for fast RGB -> luminance calculation. */
  1385. /* taken from ppmtopgm.c   -IUW */
  1386.  
  1387. static int times77[256] =
  1388. {
  1389.   0, 77, 154, 231, 308, 385, 462, 539,
  1390.   616, 693, 770, 847, 924, 1001, 1078, 1155,
  1391.   1232, 1309, 1386, 1463, 1540, 1617, 1694, 1771,
  1392.   1848, 1925, 2002, 2079, 2156, 2233, 2310, 2387,
  1393.   2464, 2541, 2618, 2695, 2772, 2849, 2926, 3003,
  1394.   3080, 3157, 3234, 3311, 3388, 3465, 3542, 3619,
  1395.   3696, 3773, 3850, 3927, 4004, 4081, 4158, 4235,
  1396.   4312, 4389, 4466, 4543, 4620, 4697, 4774, 4851,
  1397.   4928, 5005, 5082, 5159, 5236, 5313, 5390, 5467,
  1398.   5544, 5621, 5698, 5775, 5852, 5929, 6006, 6083,
  1399.   6160, 6237, 6314, 6391, 6468, 6545, 6622, 6699,
  1400.   6776, 6853, 6930, 7007, 7084, 7161, 7238, 7315,
  1401.   7392, 7469, 7546, 7623, 7700, 7777, 7854, 7931,
  1402.   8008, 8085, 8162, 8239, 8316, 8393, 8470, 8547,
  1403.   8624, 8701, 8778, 8855, 8932, 9009, 9086, 9163,
  1404.   9240, 9317, 9394, 9471, 9548, 9625, 9702, 9779,
  1405.   9856, 9933, 10010, 10087, 10164, 10241, 10318, 10395,
  1406.   10472, 10549, 10626, 10703, 10780, 10857, 10934, 11011,
  1407.   11088, 11165, 11242, 11319, 11396, 11473, 11550, 11627,
  1408.   11704, 11781, 11858, 11935, 12012, 12089, 12166, 12243,
  1409.   12320, 12397, 12474, 12551, 12628, 12705, 12782, 12859,
  1410.   12936, 13013, 13090, 13167, 13244, 13321, 13398, 13475,
  1411.   13552, 13629, 13706, 13783, 13860, 13937, 14014, 14091,
  1412.   14168, 14245, 14322, 14399, 14476, 14553, 14630, 14707,
  1413.   14784, 14861, 14938, 15015, 15092, 15169, 15246, 15323,
  1414.   15400, 15477, 15554, 15631, 15708, 15785, 15862, 15939,
  1415.   16016, 16093, 16170, 16247, 16324, 16401, 16478, 16555,
  1416.   16632, 16709, 16786, 16863, 16940, 17017, 17094, 17171,
  1417.   17248, 17325, 17402, 17479, 17556, 17633, 17710, 17787,
  1418.   17864, 17941, 18018, 18095, 18172, 18249, 18326, 18403,
  1419.   18480, 18557, 18634, 18711, 18788, 18865, 18942, 19019,
  1420.   19096, 19173, 19250, 19327, 19404, 19481, 19558, 19635};
  1421. static int times150[256] =
  1422. {
  1423.   0, 150, 300, 450, 600, 750, 900, 1050,
  1424.   1200, 1350, 1500, 1650, 1800, 1950, 2100, 2250,
  1425.   2400, 2550, 2700, 2850, 3000, 3150, 3300, 3450,
  1426.   3600, 3750, 3900, 4050, 4200, 4350, 4500, 4650,
  1427.   4800, 4950, 5100, 5250, 5400, 5550, 5700, 5850,
  1428.   6000, 6150, 6300, 6450, 6600, 6750, 6900, 7050,
  1429.   7200, 7350, 7500, 7650, 7800, 7950, 8100, 8250,
  1430.   8400, 8550, 8700, 8850, 9000, 9150, 9300, 9450,
  1431.   9600, 9750, 9900, 10050, 10200, 10350, 10500, 10650,
  1432.   10800, 10950, 11100, 11250, 11400, 11550, 11700, 11850,
  1433.   12000, 12150, 12300, 12450, 12600, 12750, 12900, 13050,
  1434.   13200, 13350, 13500, 13650, 13800, 13950, 14100, 14250,
  1435.   14400, 14550, 14700, 14850, 15000, 15150, 15300, 15450,
  1436.   15600, 15750, 15900, 16050, 16200, 16350, 16500, 16650,
  1437.   16800, 16950, 17100, 17250, 17400, 17550, 17700, 17850,
  1438.   18000, 18150, 18300, 18450, 18600, 18750, 18900, 19050,
  1439.   19200, 19350, 19500, 19650, 19800, 19950, 20100, 20250,
  1440.   20400, 20550, 20700, 20850, 21000, 21150, 21300, 21450,
  1441.   21600, 21750, 21900, 22050, 22200, 22350, 22500, 22650,
  1442.   22800, 22950, 23100, 23250, 23400, 23550, 23700, 23850,
  1443.   24000, 24150, 24300, 24450, 24600, 24750, 24900, 25050,
  1444.   25200, 25350, 25500, 25650, 25800, 25950, 26100, 26250,
  1445.   26400, 26550, 26700, 26850, 27000, 27150, 27300, 27450,
  1446.   27600, 27750, 27900, 28050, 28200, 28350, 28500, 28650,
  1447.   28800, 28950, 29100, 29250, 29400, 29550, 29700, 29850,
  1448.   30000, 30150, 30300, 30450, 30600, 30750, 30900, 31050,
  1449.   31200, 31350, 31500, 31650, 31800, 31950, 32100, 32250,
  1450.   32400, 32550, 32700, 32850, 33000, 33150, 33300, 33450,
  1451.   33600, 33750, 33900, 34050, 34200, 34350, 34500, 34650,
  1452.   34800, 34950, 35100, 35250, 35400, 35550, 35700, 35850,
  1453.   36000, 36150, 36300, 36450, 36600, 36750, 36900, 37050,
  1454.   37200, 37350, 37500, 37650, 37800, 37950, 38100, 38250};
  1455. static int times29[256] =
  1456. {
  1457.   0, 29, 58, 87, 116, 145, 174, 203,
  1458.   232, 261, 290, 319, 348, 377, 406, 435,
  1459.   464, 493, 522, 551, 580, 609, 638, 667,
  1460.   696, 725, 754, 783, 812, 841, 870, 899,
  1461.   928, 957, 986, 1015, 1044, 1073, 1102, 1131,
  1462.   1160, 1189, 1218, 1247, 1276, 1305, 1334, 1363,
  1463.   1392, 1421, 1450, 1479, 1508, 1537, 1566, 1595,
  1464.   1624, 1653, 1682, 1711, 1740, 1769, 1798, 1827,
  1465.   1856, 1885, 1914, 1943, 1972, 2001, 2030, 2059,
  1466.   2088, 2117, 2146, 2175, 2204, 2233, 2262, 2291,
  1467.   2320, 2349, 2378, 2407, 2436, 2465, 2494, 2523,
  1468.   2552, 2581, 2610, 2639, 2668, 2697, 2726, 2755,
  1469.   2784, 2813, 2842, 2871, 2900, 2929, 2958, 2987,
  1470.   3016, 3045, 3074, 3103, 3132, 3161, 3190, 3219,
  1471.   3248, 3277, 3306, 3335, 3364, 3393, 3422, 3451,
  1472.   3480, 3509, 3538, 3567, 3596, 3625, 3654, 3683,
  1473.   3712, 3741, 3770, 3799, 3828, 3857, 3886, 3915,
  1474.   3944, 3973, 4002, 4031, 4060, 4089, 4118, 4147,
  1475.   4176, 4205, 4234, 4263, 4292, 4321, 4350, 4379,
  1476.   4408, 4437, 4466, 4495, 4524, 4553, 4582, 4611,
  1477.   4640, 4669, 4698, 4727, 4756, 4785, 4814, 4843,
  1478.   4872, 4901, 4930, 4959, 4988, 5017, 5046, 5075,
  1479.   5104, 5133, 5162, 5191, 5220, 5249, 5278, 5307,
  1480.   5336, 5365, 5394, 5423, 5452, 5481, 5510, 5539,
  1481.   5568, 5597, 5626, 5655, 5684, 5713, 5742, 5771,
  1482.   5800, 5829, 5858, 5887, 5916, 5945, 5974, 6003,
  1483.   6032, 6061, 6090, 6119, 6148, 6177, 6206, 6235,
  1484.   6264, 6293, 6322, 6351, 6380, 6409, 6438, 6467,
  1485.   6496, 6525, 6554, 6583, 6612, 6641, 6670, 6699,
  1486.   6728, 6757, 6786, 6815, 6844, 6873, 6902, 6931,
  1487.   6960, 6989, 7018, 7047, 7076, 7105, 7134, 7163,
  1488.   7192, 7221, 7250, 7279, 7308, 7337, 7366, 7395};
  1489.  
  1490. /************ parse options and figure out what kind of ILBM to write ************/
  1491.  
  1492. static int get_int_val ARGS((char *string, char *option, int bot, int top));
  1493. static int get_compr_type ARGS((char *string));
  1494.  
  1495. #define NEWDEPTH(pix, table)    PPM_ASSIGN((pix), (table)[PPM_GETR(pix)], (table)[PPM_GETG(pix)], (table)[PPM_GETB(pix)])
  1496.  
  1497. int main(argc, argv)
  1498.     int argc;
  1499.     char *argv[];
  1500. {
  1501.   FILE *ifp;
  1502.   int argn, rows, cols, format, colors, nPlanes;
  1503.   int ifmode, forcemode, maxplanes, fixplanes, hambits, mode;
  1504.  
  1505. #define MAXCOLORS       (1<<maxplanes)
  1506.   pixval maxval;
  1507.   colorhist_vector chv;
  1508.   DirectColor dcol;
  1509.   char *mapfile;
  1510.   char *usage =
  1511.   "[-ecs|-aga] [-ham6|-ham8] [-maxplanes|-mp n] [-fixplanes|-fp n]\
  1512.  [-normal|-hamif|-hamforce|-24if|-24force|-dcif|-dcforce|-cmaponly]\
  1513.  [-hambits|-hamplanes n] [-dcbits|-dcplanes r g b] [-hires] [-lace]\
  1514.  [-floyd|-fs] [-compress|-nocompress] [-cmethod none|byterun1]\
  1515.  [-map ppmfile] [-savemem] [ppmfile]";
  1516.  
  1517.   ppm_init(&argc, argv);
  1518.  
  1519.   ifmode = MODE_NONE;
  1520.   forcemode = MODE_NONE;
  1521.   maxplanes = DEF_MAXPLANES;
  1522.   fixplanes = 0;
  1523.   hambits = DEF_HAMPLANES;
  1524.   mapfile = NULL;
  1525.   dcol.r = dcol.g = dcol.b = DEF_DCOLPLANES;
  1526.  
  1527.   argn = 1;
  1528.   while (argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0') {
  1529.     if (pm_keymatch(argv[argn], "-maxplanes", 4) || pm_keymatch(argv[argn], "-mp", 3)) {
  1530.       if (++argn >= argc)
  1531.     pm_usage(usage);
  1532.       maxplanes = get_int_val(argv[argn], argv[argn - 1], 1, MAXPLANES);
  1533.       fixplanes = 0;
  1534.     }
  1535.     else if (pm_keymatch(argv[argn], "-fixplanes", 4) || pm_keymatch(argv[argn], "-fp", 3)) {
  1536.       if (++argn >= argc)
  1537.     pm_usage(usage);
  1538.       fixplanes = get_int_val(argv[argn], argv[argn - 1], 1, MAXPLANES);
  1539.       maxplanes = fixplanes;
  1540.     }
  1541.     else if (pm_keymatch(argv[argn], "-map", 4)) {
  1542.       if (++argn >= argc)
  1543.     pm_usage(usage);
  1544.       mapfile = argv[argn];
  1545.     }
  1546.     else if (pm_keymatch(argv[argn], "-cmaponly", 3)) {
  1547.       forcemode = MODE_CMAP;
  1548.     }
  1549.     else if (pm_keymatch(argv[argn], "-hambits", 5) || pm_keymatch(argv[argn], "-hamplanes", 5)) {
  1550.       if (++argn > argc)
  1551.     pm_usage(usage);
  1552.       hambits = get_int_val(argv[argn], argv[argn - 1], 3, MAXPLANES);
  1553.     }
  1554.     else if (pm_keymatch(argv[argn], "-ham6", 5)) {
  1555.       hambits = ECS_HAMPLANES;
  1556.       forcemode = MODE_HAM;
  1557.     }
  1558.     else if (pm_keymatch(argv[argn], "-ham8", 5)) {
  1559.       hambits = AGA_HAMPLANES;
  1560.       forcemode = MODE_HAM;
  1561.     }
  1562.     else if (pm_keymatch(argv[argn], "-lace", 2)) {
  1563. #ifdef ILBM_PCHG
  1564.       slicesize = 2;
  1565. #endif
  1566.       viewportmodes |= vmLACE;
  1567.     }
  1568.     else if (pm_keymatch(argv[argn], "-nolace", 4)) {
  1569. #ifdef ILBM_PCHG
  1570.       slicesize = 1;
  1571. #endif
  1572.       viewportmodes &= ~vmLACE;
  1573.     }
  1574.     else if (pm_keymatch(argv[argn], "-hires", 3))
  1575.       viewportmodes |= vmHIRES;
  1576.     else if (pm_keymatch(argv[argn], "-nohires", 5))
  1577.       viewportmodes &= ~vmHIRES;
  1578.     else if (pm_keymatch(argv[argn], "-ecs", 2)) {
  1579.       maxplanes = ECS_MAXPLANES;
  1580.       hambits = ECS_HAMPLANES;
  1581.     }
  1582.     else if (pm_keymatch(argv[argn], "-aga", 2)) {
  1583.       maxplanes = AGA_MAXPLANES;
  1584.       hambits = AGA_HAMPLANES;
  1585.     }
  1586.     else if (pm_keymatch(argv[argn], "-hamif", 5))
  1587.       ifmode = MODE_HAM;
  1588.     else if (pm_keymatch(argv[argn], "-nohamif", 7)) {
  1589.       if (ifmode == MODE_HAM)
  1590.     ifmode = MODE_NONE;
  1591.     }
  1592.     else if (pm_keymatch(argv[argn], "-hamforce", 5))
  1593.       forcemode = MODE_HAM;
  1594.     else if (pm_keymatch(argv[argn], "-nohamforce", 7)) {
  1595.       if (forcemode == MODE_HAM)
  1596.     forcemode = MODE_NONE;
  1597.     }
  1598.     else if (pm_keymatch(argv[argn], "-24if", 4))
  1599.       ifmode = MODE_24;
  1600.     else if (pm_keymatch(argv[argn], "-no24if", 6)) {
  1601.       if (ifmode == MODE_24)
  1602.     ifmode = MODE_NONE;
  1603.     }
  1604.     else if (pm_keymatch(argv[argn], "-24force", 4))
  1605.       forcemode = MODE_24;
  1606.     else if (pm_keymatch(argv[argn], "-no24force", 6)) {
  1607.       if (forcemode == MODE_24)
  1608.     forcemode = MODE_NONE;
  1609.     }
  1610.     else if (pm_keymatch(argv[argn], "-dcif", 4)) {
  1611.       ifmode = MODE_DIRECT;
  1612.     }
  1613.     else if (pm_keymatch(argv[argn], "-nodcif", 6)) {
  1614.       if (ifmode == MODE_DIRECT)
  1615.     ifmode = MODE_NONE;
  1616.     }
  1617.     else if (pm_keymatch(argv[argn], "-dcforce", 4)) {
  1618.       forcemode = MODE_DIRECT;
  1619.     }
  1620.     else if (pm_keymatch(argv[argn], "-nodcforce", 6)) {
  1621.       if (forcemode == MODE_DIRECT)
  1622.     forcemode = MODE_NONE;
  1623.     }
  1624.     else if (pm_keymatch(argv[argn], "-dcbits", 4) || pm_keymatch(argv[argn], "-dcplanes", 4)) {
  1625.       char *option = argv[argn];
  1626.  
  1627.       if (++argn >= argc)
  1628.     pm_usage(usage);
  1629.       dcol.r = (unsigned char)get_int_val(argv[argn], option, 1, MAXPLANES);
  1630.       if (++argn >= argc)
  1631.     pm_usage(usage);
  1632.       dcol.g = (unsigned char)get_int_val(argv[argn], option, 1, MAXPLANES);
  1633.       if (++argn >= argc)
  1634.     pm_usage(usage);
  1635.       dcol.b = (unsigned char)get_int_val(argv[argn], option, 1, MAXPLANES);
  1636.     }
  1637.     else if (pm_keymatch(argv[argn], "-normal", 4)) {
  1638.       ifmode = forcemode = MODE_NONE;
  1639.       compr_type = DEF_COMPRESSION;
  1640.     }
  1641.     else if (pm_keymatch(argv[argn], "-compress", 3)) {
  1642.       compr_force = 1;
  1643.       if (compr_type == cmpNone)
  1644.     if (DEF_COMPRESSION == cmpNone)
  1645.       compr_type = cmpByteRun1;
  1646.     else
  1647.       compr_type = DEF_COMPRESSION;
  1648.     }
  1649.     else if (pm_keymatch(argv[argn], "-nocompress", 4)) {
  1650.       compr_force = 0;
  1651.       compr_type = cmpNone;
  1652.     }
  1653.     else if (pm_keymatch(argv[argn], "-cmethod", 4)) {
  1654.       if (++argn >= argc)
  1655.     pm_usage(usage);
  1656.       compr_type = get_compr_type(argv[argn]);
  1657.     }
  1658.     else if (pm_keymatch(argv[argn], "-savemem", 2))
  1659.       savemem = 1;
  1660.     else if (pm_keymatch(argv[argn], "-fs1", 4))        /* EXPERIMENTAL */
  1661.       floyd = 2;
  1662.     else if (pm_keymatch(argv[argn], "-floyd", 3) || pm_keymatch(argv[argn], "-fs", 3))
  1663.       floyd = 1;
  1664.     else if (pm_keymatch(argv[argn], "-nofloyd", 5) || pm_keymatch(argv[argn], "-nofs", 5))
  1665.       floyd = 0;
  1666.     else
  1667.       pm_usage(usage);
  1668.     ++argn;
  1669.   }
  1670.  
  1671.   if (argn < argc) {
  1672.     ifp = pm_openr(argv[argn]);
  1673.     ++argn;
  1674.   }
  1675.   else
  1676.     ifp = stdin;
  1677.  
  1678.   if (argn != argc)
  1679.     pm_usage(usage);
  1680.  
  1681.   if (forcemode != MODE_NONE && mapfile != NULL)
  1682.     pm_message("warning - mapfile only used for normal ILBMs");
  1683.  
  1684.   mode = forcemode;
  1685.   switch (forcemode) {
  1686.     case MODE_HAM:
  1687.       /* grayscale colormap for now - we don't need to read the whole
  1688.        * file into memory and can use row-by-row operation */
  1689.       init_read(ifp, &cols, &rows, &maxval, &format, 0);
  1690.       pm_message("hamforce option used - proceeding to write a HAM%d file", hambits);
  1691.       break;
  1692.     case MODE_24:
  1693.       init_read(ifp, &cols, &rows, &maxval, &format, 0);
  1694.       pm_message("24force option used - proceeding to write a 24bit file");
  1695.       break;
  1696.     case MODE_DIRECT:
  1697.       init_read(ifp, &cols, &rows, &maxval, &format, 0);
  1698.       pm_message("dcforce option used - proceeding to write a %d:%d:%d direct color file",
  1699.          dcol.r, dcol.g, dcol.b);
  1700.       break;
  1701.     case MODE_CMAP:
  1702.       /* must read the whole file into memory */
  1703.       init_read(ifp, &cols, &rows, &maxval, &format, 1);
  1704.  
  1705.       /* Figure out the colormap. */
  1706.       pm_message("computing colormap...");
  1707.       chv = ppm_computecolorhist(pixels, cols, rows, MAXCMAPCOLORS, &colors);
  1708.       if (chv == (colorhist_vector) NULL)
  1709.     pm_error("too many colors - try doing a 'ppmquant %d'", MAXCMAPCOLORS);
  1710.       pm_message("%d colors found", colors);
  1711.       break;
  1712.     default:
  1713.       /* must read the whole file into memory */
  1714.       init_read(ifp, &cols, &rows, &maxval, &format, 1);
  1715.  
  1716.       /* Figure out the colormap. */
  1717.       if (mapfile) {
  1718.     int mapcols, maprows, row, col;
  1719.     pixel **mappixels, *pP;
  1720.     pixval mapmaxval;
  1721.     FILE *mapfp;
  1722.  
  1723.     pm_message("reading colormap file...");
  1724.     mapfp = pm_openr(mapfile);
  1725.     mappixels = ppm_readppm(mapfp, &mapcols, &maprows, &mapmaxval);
  1726.     pm_close(mapfp);
  1727.     if (mapcols == 0 || maprows == 0)
  1728.       pm_error("null colormap??");
  1729.  
  1730.     /* if the maxvals of the ppmfile and the mapfile are the same,
  1731.      * then the scaling to MAXCOLVAL (if necessary) will be done by
  1732.      * the write_std_cmap() function.
  1733.      * Otherwise scale them both to MAXCOLVAL.
  1734.      */
  1735.     if (maxval != mapmaxval) {
  1736.       if (mapmaxval != MAXCOLVAL) {
  1737.         pixval *table;
  1738.  
  1739.         pm_message("colormap maxval is not %d - rescaling colormap...", MAXCOLVAL);
  1740.         table = make_val_table(mapmaxval, MAXCOLVAL);
  1741.         for (row = 0; row < maprows; ++row)
  1742.           for (col = 0, pP = mappixels[row]; col < mapcols; ++col, ++pP)
  1743.         NEWDEPTH(*pP, table);                /* was PPM_DEPTH( *pP, *pP, mapmaxval, MAXCOLVAL ); */
  1744.         mapmaxval = MAXCOLVAL;
  1745.         free(table);
  1746.       }
  1747.  
  1748.       if (maxval != mapmaxval) {
  1749.         pixval *table;
  1750.  
  1751.         pm_message("rescaling colors of picture...");
  1752.         table = make_val_table(maxval, mapmaxval);
  1753.         for (row = 0; row < rows; ++row)
  1754.           for (col = 0, pP = pixels[row]; col < cols; ++col, ++pP)
  1755.         NEWDEPTH(*pP, table);                /* was PPM_DEPTH( *pP, *pP, maxval, mapmaxval ); */
  1756.         maxval = mapmaxval;
  1757.         free(table);
  1758.       }
  1759.     }
  1760.  
  1761.     pm_message("computing colormap...");
  1762.     chv = ppm_computecolorhist(mappixels, mapcols, maprows, MAXCMAPCOLORS, &colors);
  1763.     ppm_freearray(mappixels, maprows);
  1764.     if (chv == (colorhist_vector) 0)
  1765.       pm_error("too many colors in colormap!");
  1766.     pm_message("%d colors found in colormap", colors);
  1767.  
  1768.     nPlanes = fixplanes = maxplanes = colorstobpp(colors);
  1769.       }
  1770.       else {                            /* no mapfile */
  1771.     pm_message("computing colormap...");
  1772.     chv = ppm_computecolorhist(pixels, cols, rows, MAXCOLORS, &colors);
  1773.     if (chv == (colorhist_vector) 0) {
  1774.       /* too many colors */
  1775.       mode = ifmode;
  1776.       switch (ifmode) {
  1777.         case MODE_HAM:
  1778.           pm_message("too many colors - proceeding to write a HAM%d file", hambits);
  1779.           pm_message("if you want a non-HAM file, try doing a 'ppmquant %d'", MAXCOLORS);
  1780.           break;
  1781.         case MODE_24:
  1782.           pm_message("too many colors - proceeding to write a 24bit file");
  1783.           pm_message("if you want a non-24bit file, try doing a 'ppmquant %d'", MAXCOLORS);
  1784.           break;
  1785.         case MODE_DIRECT:
  1786.           pm_message("too many colors - proceeding to write a %d:%d:%d direct color file",
  1787.              dcol.r, dcol.g, dcol.b);
  1788.           pm_message("if you want a non-direct-color file, try doing a 'ppmquant %d'", MAXCOLORS);
  1789.           break;
  1790.         default:
  1791.           pm_message("too many colors for %d planes", maxplanes);
  1792.           pm_message("either use -hamif/-hamforce/-24if/-24force/-dcif/-dcforce/-maxplanes,");
  1793.           pm_error("or try doing a 'ppmquant %d'", MAXCOLORS);
  1794.           break;
  1795.       }
  1796.     }
  1797.     else {
  1798.       pm_message("%d colors found", colors);
  1799.       nPlanes = colorstobpp(colors);
  1800.       if (fixplanes > nPlanes)
  1801.         nPlanes = fixplanes;
  1802.     }
  1803.       }
  1804.       break;
  1805.   }
  1806.  
  1807.   if (mode != MODE_CMAP) {
  1808.     register int i;
  1809.     coded_rowbuf = MALLOC(RowBytes(cols), unsigned char);
  1810.  
  1811.     for (i = 0; i < RowBytes(cols); i++)
  1812.       coded_rowbuf[i] = 0;
  1813.     if (DO_COMPRESS)
  1814.       compr_rowbuf = MALLOC(WORSTCOMPR(RowBytes(cols)), unsigned char);
  1815.   }
  1816.  
  1817.   switch (mode) {
  1818.     case MODE_HAM:{
  1819.     int nocolor;
  1820.  
  1821.     nocolor = !(PPM_FORMAT_TYPE(format) == PPM_TYPE);
  1822.     if (nocolor)
  1823.       floyd = 0;
  1824.  
  1825.     viewportmodes |= vmHAM;
  1826.     ppm_to_ham(ifp, cols, rows, maxval, hambits, nocolor);
  1827.       }
  1828.       break;
  1829.     case MODE_24:
  1830.       ppm_to_24(ifp, cols, rows, maxval);
  1831.       break;
  1832.     case MODE_DIRECT:
  1833.       ppm_to_direct(ifp, cols, rows, maxval, &dcol);
  1834.       break;
  1835.     case MODE_CMAP:
  1836.       ppm_to_cmap(maxval, chv, colors);
  1837.       break;
  1838.     default:
  1839.       if (mapfile == NULL)
  1840.     floyd = 0;                        /* would only slow down conversion */
  1841.       ppm_to_std(ifp, cols, rows, maxval, chv, colors, nPlanes);
  1842.       break;
  1843.   }
  1844.   pm_close(ifp);
  1845.   exit(0);
  1846.   /*NOTREACHED */
  1847. }
  1848.  
  1849. static int get_int_val(string, option, bot, top)
  1850.     char *string, *option;
  1851.     int bot, top;
  1852. {
  1853.   int val;
  1854.  
  1855.   if (sscanf(string, "%d", &val) != 1)
  1856.     pm_error("option \"%s\" needs integer argument", option);
  1857.  
  1858.   if (val < bot || val > top)
  1859.     pm_error("option \"%s\" argument value out of range (%d..%d)", option, bot, top);
  1860.  
  1861.   return val;
  1862. }
  1863.  
  1864. static int get_compr_type(string)
  1865.     char *string;
  1866. {
  1867.   int i;
  1868.  
  1869.   for (i = 0; i <= cmpMAXKNOWN; i++) {
  1870.     if (strcmp(string, cmpNAME[i]) == 0)
  1871.       return i;
  1872.   }
  1873.   pm_message("unknown compression method: %s", string);
  1874.   pm_message("using default compression (%s)", cmpNAME[DEF_COMPRESSION]);
  1875.   return DEF_COMPRESSION;
  1876. }
  1877.  
  1878. /************ colormap file ************/
  1879.  
  1880. static void ppm_to_cmap(maxval, chv, colors)
  1881.     int maxval;
  1882.     colorhist_vector chv;
  1883.     int colors;
  1884. {
  1885.   int formsize, cmapsize;
  1886.  
  1887.   cmapsize = colors * 3;
  1888.  
  1889.   formsize =
  1890.     4 +                                /* ILBM */
  1891.     4 + 4 + BitMapHeaderSize +                    /* BMHD size header */
  1892.     4 + 4 + cmapsize + PAD(cmapsize);                /* CMAP size colormap */
  1893.  
  1894.   write_form_ilbm(formsize);
  1895.   write_bmhd(0, 0, 0);
  1896.   write_std_cmap(chv, colors, maxval);
  1897. }
  1898.  
  1899. /************ HAM ************/
  1900.  
  1901. static long do_ham_body ARGS((FILE * ifp, FILE * ofp, int cols, int rows, pixval maxval, pixval hammaxval, int nPlanes, int colbits, int no));
  1902.  
  1903. static void ppm_to_ham(fp, cols, rows, maxval, hambits, nocolor)
  1904.     FILE *fp;
  1905.     int cols, rows, maxval, hambits, nocolor;
  1906. {
  1907.   int colors, colbits, nPlanes, i, hammaxval;
  1908.   long oldsize, bodysize, formsize, cmapsize;
  1909.   pixval *table = NULL;
  1910.  
  1911.   colbits = hambits - 2;
  1912.   colors = 1 << colbits;
  1913.   hammaxval = pm_bitstomaxval(colbits);
  1914.   nPlanes = hambits;
  1915.   cmapsize = colors * 3;
  1916.  
  1917.   bodysize = oldsize = rows * nPlanes * RowBytes(cols);
  1918.   if (DO_COMPRESS) {
  1919.     alloc_body_array(rows, nPlanes);
  1920.     bodysize = do_ham_body(fp, NULL, cols, rows, maxval, hammaxval, nPlanes, colbits, nocolor);
  1921.     if (bodysize > oldsize)
  1922.       pm_message("warning - %s compression increases BODY size by %d%%", cmpNAME[compr_type], 100 * (bodysize - oldsize) / oldsize);
  1923.     else
  1924.       pm_message("BODY compression (%s): %d%%", cmpNAME[compr_type], 100 * (oldsize - bodysize) / oldsize);
  1925.   }
  1926.  
  1927.   formsize =
  1928.     4 +                                /* ILBM */
  1929.     4 + 4 + BitMapHeaderSize +                    /* BMHD size header */
  1930.     CAMGSIZE +                            /* 0 or CAMG size val */
  1931.     4 + 4 + cmapsize + PAD(cmapsize) +                /* CMAP size colormap */
  1932.     4 + 4 + bodysize + PAD(bodysize);                /* BODY size data */
  1933.  
  1934.   write_form_ilbm(formsize);
  1935.   write_bmhd(cols, rows, nPlanes);
  1936.   write_camg();
  1937.  
  1938.   /* write grayscale colormap */
  1939.   put_fourchars("CMAP");
  1940.   put_big_long(cmapsize);
  1941.   table = make_val_table(hammaxval, MAXCOLVAL);
  1942.   for (i = 0; i < colors; i++) {
  1943.     put_byte(table[i]);                        /* red */
  1944.     put_byte(table[i]);                        /* green */
  1945.     put_byte(table[i]);                        /* blue */
  1946.   }
  1947.   free(table);
  1948.   if (odd(cmapsize))
  1949.     put_byte(0);
  1950.  
  1951.   /* write body */
  1952.   put_fourchars("BODY");
  1953.   put_big_long(bodysize);
  1954.   if (DO_COMPRESS)
  1955.     write_body();
  1956.   else
  1957.     do_ham_body(fp, stdout, cols, rows, maxval, hammaxval, nPlanes, colbits, nocolor);
  1958.   if (odd(bodysize))
  1959.     put_byte(0);
  1960. }
  1961.  
  1962. static long do_ham_body(ifp, ofp, cols, rows, maxval, hammaxval, nPlanes, colbits, nocolor)
  1963.     FILE *ifp, *ofp;
  1964.     int cols, rows;
  1965.     pixval maxval, hammaxval;
  1966.     int nPlanes, colbits, nocolor;
  1967. {
  1968.   register int col, row;
  1969.   pixel *pP;
  1970.   pixval *table = NULL;
  1971.   rawtype *raw_rowbuf;
  1972.   floydinfo *fi;
  1973.   long bodysize = 0;
  1974.  
  1975.   raw_rowbuf = MALLOC(cols, rawtype);
  1976.  
  1977.   if (hammaxval != maxval)
  1978.     table = make_val_table(maxval, hammaxval);
  1979.  
  1980.   if (floyd) {
  1981.     fi = init_floyd(cols, maxval, 0);
  1982.   }
  1983.  
  1984.   for (row = 0; row < rows; row++) {
  1985.     register int noprev, pr, pg, pb, r, g, b, l;
  1986.     int fpr, fpg, fpb;                        /* unscaled previous color values, for floyd */
  1987.  
  1988.     pP = next_pixrow(ifp, row);
  1989.     if (floyd)
  1990.       begin_floyd_row(fi, pP);
  1991.  
  1992.     noprev = 1;
  1993.     for (col = 0; col < cols; col++, pP++) {
  1994.       int fr, fg, fb, fl;                    /* unscaled color values, for floyd */
  1995.  
  1996.       if (floyd)
  1997.     pP = next_floyd_pixel(fi);
  1998.  
  1999.       r = fr = PPM_GETR(*pP);
  2000.       g = fg = PPM_GETG(*pP);
  2001.       b = fb = PPM_GETB(*pP);
  2002.       if (maxval <= 255)                    /* Use fast approximation to 0.299 r + 0.587 g + 0.114 b. */
  2003.     l = fl = (int)((times77[r] + times150[g] + times29[b] + 128) >> 8);
  2004.       else                            /* Can't use fast approximation, so fall back on floats. */
  2005.     l = fl = (int)(PPM_LUMIN(*pP) + 0.5);            /* -IUW added '+ 0.5' */
  2006.  
  2007.       if (table) {
  2008.     r = table[r];
  2009.     g = table[g];
  2010.     b = table[b];
  2011.     l = table[l];
  2012.       }
  2013.  
  2014.       if (noprev || nocolor) {
  2015.     /* No previous pixels, gotta use the gray option. */
  2016.     raw_rowbuf[col] = l /* + (HAMCODE_CMAP << colbits) */ ;
  2017.     pr = pg = pb = l;
  2018.     fpr = fpg = fpb = fl;
  2019.     noprev = 0;
  2020.       }
  2021.       else {
  2022.     register int dred, dgreen, dblue, dgray;
  2023.  
  2024.     /* Compute distances for the four options. */
  2025.     dred = abs(g - pg) + abs(b - pb);
  2026.     dgreen = abs(r - pr) + abs(b - pb);
  2027.     dblue = abs(r - pr) + abs(g - pg);
  2028.     dgray = abs(r - l) + abs(g - l) + abs(b - l);
  2029.  
  2030.     /* simply doing  raw_rowbuf[col] = ...
  2031.      * is ok here because there is no fs-alternation performed
  2032.      * for HAM.  Otherwise we would have to do
  2033.      *     if( floyd )  raw_rowbuf[fi->col] = ...
  2034.      *     else         raw_rowbuf[col] = ...
  2035.      */
  2036.     if (dgray <= dred && dgray <= dgreen && dgray <= dblue) {    /* -IUW  '<=' was '<'  */
  2037.       raw_rowbuf[col] = l /* + (HAMCODE_CMAP << colbits) */ ;
  2038.       pr = pg = pb = l;
  2039.       fpr = fpg = fpb = fl;
  2040.     }
  2041.     else if (dblue <= dred && dblue <= dgreen) {
  2042.       raw_rowbuf[col] = b + (HAMCODE_BLUE << colbits);
  2043.       pb = b;
  2044.       fpb = fb;
  2045.     }
  2046.     else if (dred <= dgreen) {
  2047.       raw_rowbuf[col] = r + (HAMCODE_RED << colbits);
  2048.       pr = r;
  2049.       fpr = fr;
  2050.     }
  2051.     else {
  2052.       raw_rowbuf[col] = g + (HAMCODE_GREEN << colbits);
  2053.       pg = g;
  2054.       fpg = fg;
  2055.     }
  2056.       }
  2057.       if (floyd)
  2058.     update_floyd_pixel(fi, fpr, fpg, fpb);
  2059.     }
  2060.     bodysize += encode_row(ofp, raw_rowbuf, cols, nPlanes);
  2061.     if (floyd)
  2062.       end_floyd_row(fi);
  2063.   }
  2064.   /* clean up */
  2065.   if (table)
  2066.     free(table);
  2067.   free(raw_rowbuf);
  2068.   if (floyd)
  2069.     free_floyd(fi);
  2070.  
  2071.   return bodysize;
  2072. }
  2073.  
  2074. /************ 24bit ************/
  2075.  
  2076. static long do_24_body ARGS((FILE * ifp, FILE * ofp, int cols, int rows, pixval maxval));
  2077.  
  2078. static void ppm_to_24(fp, cols, rows, maxval)
  2079.     FILE *fp;
  2080.     int cols, rows, maxval;
  2081. {
  2082.   int nPlanes;
  2083.   long bodysize, oldsize, formsize;
  2084.  
  2085.   nPlanes = 24;
  2086.  
  2087.   bodysize = oldsize = rows * nPlanes * RowBytes(cols);
  2088.   if (DO_COMPRESS) {
  2089.     alloc_body_array(rows, nPlanes);
  2090.     bodysize = do_24_body(fp, NULL, cols, rows, maxval);
  2091.     if (bodysize > oldsize)
  2092.       pm_message("warning - %s compression increases BODY size by %d%%", cmpNAME[compr_type], 100 * (bodysize - oldsize) / oldsize);
  2093.     else
  2094.       pm_message("BODY compression (%s): %d%%", cmpNAME[compr_type], 100 * (oldsize - bodysize) / oldsize);
  2095.   }
  2096.  
  2097.   formsize =
  2098.     4 +                                /* ILBM */
  2099.     4 + 4 + BitMapHeaderSize +                    /* BMHD size header */
  2100.     CAMGSIZE +                            /* 0 or CAMG size val */
  2101.     4 + 4 + bodysize + PAD(bodysize);                /* BODY size data */
  2102.  
  2103.   write_form_ilbm(formsize);
  2104.   write_bmhd(cols, rows, nPlanes);
  2105.   write_camg();
  2106.  
  2107.   /* write body */
  2108.   put_fourchars("BODY");
  2109.   put_big_long(bodysize);
  2110.   if (DO_COMPRESS)
  2111.     write_body();
  2112.   else
  2113.     do_24_body(fp, stdout, cols, rows, maxval);
  2114.   if (odd(bodysize))
  2115.     put_byte(0);
  2116. }
  2117.  
  2118. static long do_24_body(ifp, ofp, cols, rows, maxval)
  2119.     FILE *ifp, *ofp;
  2120.     int cols, rows;
  2121.     pixval maxval;
  2122. {
  2123.   register int row, col;
  2124.   pixel *pP;
  2125.   pixval *table = NULL;
  2126.   long bodysize = 0;
  2127.   rawtype *redbuf, *greenbuf, *bluebuf;
  2128.  
  2129.   redbuf = MALLOC(cols, rawtype);
  2130.   greenbuf = MALLOC(cols, rawtype);
  2131.   bluebuf = MALLOC(cols, rawtype);
  2132.  
  2133.   if (maxval != MAXCOLVAL) {
  2134.     pm_message("maxval is not %d - automatically rescaling colors", MAXCOLVAL);
  2135.     table = make_val_table(maxval, MAXCOLVAL);
  2136.   }
  2137.  
  2138.   for (row = 0; row < rows; row++) {
  2139.     pP = next_pixrow(ifp, row);
  2140.     if (table) {
  2141.       for (col = 0; col < cols; col++, pP++) {
  2142.     redbuf[col] = table[PPM_GETR(*pP)];
  2143.     greenbuf[col] = table[PPM_GETG(*pP)];
  2144.     bluebuf[col] = table[PPM_GETB(*pP)];
  2145.       }
  2146.     }
  2147.     else {
  2148.       for (col = 0; col < cols; col++, pP++) {
  2149.     redbuf[col] = PPM_GETR(*pP);
  2150.     greenbuf[col] = PPM_GETG(*pP);
  2151.     bluebuf[col] = PPM_GETB(*pP);
  2152.       }
  2153.     }
  2154.     bodysize += encode_row(ofp, redbuf, cols, 8);
  2155.     bodysize += encode_row(ofp, greenbuf, cols, 8);
  2156.     bodysize += encode_row(ofp, bluebuf, cols, 8);
  2157.   }
  2158.   /* clean up */
  2159.   if (table)
  2160.     free(table);
  2161.   free(redbuf);
  2162.   free(greenbuf);
  2163.   free(bluebuf);
  2164.  
  2165.   return bodysize;
  2166. }
  2167.  
  2168. /************ direct color ************/
  2169.  
  2170. static long do_direct_body ARGS((FILE * ifp, FILE * ofp, int cols, int rows, pixval maxval, DirectColor * dcol));
  2171.  
  2172. static void ppm_to_direct(fp, cols, rows, maxval, dcol)
  2173.     FILE *fp;
  2174.     int cols, rows, maxval;
  2175.     DirectColor *dcol;
  2176. {
  2177.   int nPlanes;
  2178.   long formsize, bodysize, oldsize;
  2179.  
  2180.   nPlanes = dcol->r + dcol->g + dcol->b;
  2181.  
  2182.   bodysize = oldsize = rows * nPlanes * RowBytes(cols);
  2183.   if (DO_COMPRESS) {
  2184.     alloc_body_array(rows, nPlanes);
  2185.     bodysize = do_direct_body(fp, NULL, cols, rows, maxval, dcol);
  2186.     if (bodysize > oldsize)
  2187.       pm_message("warning - %s compression increases BODY size by %d%%", cmpNAME[compr_type], 100 * (bodysize - oldsize) / oldsize);
  2188.     else
  2189.       pm_message("BODY compression (%s): %d%%", cmpNAME[compr_type], 100 * (oldsize - bodysize) / oldsize);
  2190.   }
  2191.  
  2192.   formsize =
  2193.     4 +                                /* ILBM */
  2194.     4 + 4 + BitMapHeaderSize +                    /* BMHD size header */
  2195.     CAMGSIZE +                            /* 0 or CAMG size val */
  2196.     4 + 4 + DirectColorSize +                    /* DCOL size description */
  2197.     4 + 4 + bodysize + PAD(bodysize);                /* BODY size data */
  2198.  
  2199.   write_form_ilbm(formsize);
  2200.   write_bmhd(cols, rows, nPlanes);
  2201.   write_camg();
  2202.  
  2203.   /* write DCOL */
  2204.   put_fourchars("DCOL");
  2205.   put_big_long(DirectColorSize);
  2206.   put_byte(dcol->r);
  2207.   put_byte(dcol->g);
  2208.   put_byte(dcol->b);
  2209.   put_byte(0);                            /* pad */
  2210.  
  2211.   /* write body */
  2212.   put_fourchars("BODY");
  2213.   put_big_long(bodysize);
  2214.   if (DO_COMPRESS)
  2215.     write_body();
  2216.   else
  2217.     do_direct_body(fp, stdout, cols, rows, maxval, dcol);
  2218.   if (odd(bodysize))
  2219.     put_byte(0);
  2220. }
  2221.  
  2222. static long do_direct_body(ifp, ofp, cols, rows, maxval, dcol)
  2223.     FILE *ifp, *ofp;
  2224.     int cols, rows;
  2225.     pixval maxval;
  2226.     DirectColor *dcol;
  2227. {
  2228.   register int row, col;
  2229.   pixel *pP;
  2230.   pixval *redtable = NULL, *greentable = NULL, *bluetable = NULL;
  2231.   pixval redmaxval, greenmaxval, bluemaxval;
  2232.   rawtype *redbuf, *greenbuf, *bluebuf;
  2233.   long bodysize = 0;
  2234.  
  2235.   redbuf = MALLOC(cols, rawtype);
  2236.   greenbuf = MALLOC(cols, rawtype);
  2237.   bluebuf = MALLOC(cols, rawtype);
  2238.  
  2239.   redmaxval = pm_bitstomaxval(dcol->r);
  2240.   if (redmaxval != maxval) {
  2241.     pm_message("rescaling reds to %d bits", dcol->r);
  2242.     redtable = make_val_table(maxval, redmaxval);
  2243.   }
  2244.   greenmaxval = pm_bitstomaxval(dcol->g);
  2245.   if (greenmaxval != maxval) {
  2246.     pm_message("rescaling greens to %d bits", dcol->g);
  2247.     greentable = make_val_table(maxval, greenmaxval);
  2248.   }
  2249.   bluemaxval = pm_bitstomaxval(dcol->b);
  2250.   if (bluemaxval != maxval) {
  2251.     pm_message("rescaling blues to %d bits", dcol->b);
  2252.     bluetable = make_val_table(maxval, bluemaxval);
  2253.   }
  2254.  
  2255.   for (row = 0; row < rows; row++) {
  2256.     pP = next_pixrow(ifp, row);
  2257.     for (col = 0; col < cols; col++, pP++) {
  2258.       register pixval r, g, b;
  2259.  
  2260.       r = PPM_GETR(*pP);
  2261.       if (redtable)
  2262.     r = redtable[r];
  2263.       g = PPM_GETG(*pP);
  2264.       if (greentable)
  2265.     g = greentable[g];
  2266.       b = PPM_GETB(*pP);
  2267.       if (bluetable)
  2268.     b = bluetable[b];
  2269.  
  2270.       redbuf[col] = r;
  2271.       greenbuf[col] = g;
  2272.       bluebuf[col] = b;
  2273.     }
  2274.     bodysize += encode_row(ofp, redbuf, cols, dcol->r);
  2275.     bodysize += encode_row(ofp, greenbuf, cols, dcol->g);
  2276.     bodysize += encode_row(ofp, bluebuf, cols, dcol->b);
  2277.   }
  2278.   /* clean up */
  2279.   if (redtable)
  2280.     free(redtable);
  2281.   if (greentable)
  2282.     free(greentable);
  2283.   if (bluetable)
  2284.     free(bluetable);
  2285.   free(redbuf);
  2286.   free(greenbuf);
  2287.   free(bluebuf);
  2288.  
  2289.   return bodysize;
  2290. }
  2291.  
  2292. /************ normal colormapped ************/
  2293.  
  2294. static long do_std_body ARGS((FILE * ifp, FILE * ofp, int cols, int rows, pixval maxval, colorhist_vector chv, int colors, int nPlanes));
  2295.  
  2296. static void ppm_to_std(fp, cols, rows, maxval, chv, colors, nPlanes)
  2297.     FILE *fp;
  2298.     int cols, rows, maxval;
  2299.     colorhist_vector chv;
  2300.     int colors, nPlanes;
  2301. {
  2302.   long formsize, cmapsize, bodysize, oldsize;
  2303.  
  2304.   bodysize = oldsize = rows * nPlanes * RowBytes(cols);
  2305.   if (DO_COMPRESS) {
  2306.     alloc_body_array(rows, nPlanes);
  2307.     bodysize = do_std_body(fp, NULL, cols, rows, maxval, chv, colors, nPlanes);
  2308.     if (bodysize > oldsize)
  2309.       pm_message("warning - %s compression increases BODY size by %d%%", cmpNAME[compr_type], 100 * (bodysize - oldsize) / oldsize);
  2310.     else
  2311.       pm_message("BODY compression (%s): %d%%", cmpNAME[compr_type], 100 * (oldsize - bodysize) / oldsize);
  2312.   }
  2313.  
  2314.   cmapsize = colors * 3;
  2315.  
  2316.   formsize =
  2317.     4 +                                /* ILBM */
  2318.     4 + 4 + BitMapHeaderSize +                    /* BMHD size header */
  2319.     CAMGSIZE +                            /* 0 or CAMG size val */
  2320.     4 + 4 + cmapsize + PAD(cmapsize) +                /* CMAP size colormap */
  2321.     4 + 4 + bodysize + PAD(bodysize);                /* BODY size data */
  2322.  
  2323.   write_form_ilbm(formsize);
  2324.   write_bmhd(cols, rows, nPlanes);
  2325.   write_camg();
  2326.   write_std_cmap(chv, colors, maxval);
  2327.  
  2328.   /* write body */
  2329.   put_fourchars("BODY");
  2330.   put_big_long(bodysize);
  2331.   if (DO_COMPRESS)
  2332.     write_body();
  2333.   else
  2334.     do_std_body(fp, stdout, cols, rows, maxval, chv, colors, nPlanes);
  2335.   if (odd(bodysize))
  2336.     put_byte(0);
  2337. }
  2338.  
  2339. static long do_std_body(ifp, ofp, cols, rows, maxval, chv, colors, nPlanes)
  2340.     FILE *ifp, *ofp;
  2341.     int cols, rows;
  2342.     pixval maxval;
  2343.     colorhist_vector chv;
  2344.     int colors, nPlanes;
  2345. {
  2346.   colorhash_table cht;
  2347.   register int row, col;
  2348.   pixel *pP;
  2349.   rawtype *raw_rowbuf;
  2350.   floydinfo *fi;
  2351.   long bodysize = 0;
  2352.   short usehash = !savemem;
  2353.  
  2354.   raw_rowbuf = MALLOC(cols, rawtype);
  2355.  
  2356.   /* Make a hash table for fast color lookup. */
  2357.   cht = ppm_colorhisttocolorhash(chv, colors);
  2358.  
  2359.   if (floyd)
  2360.     fi = init_floyd(cols, maxval, 1);
  2361.  
  2362.   for (row = 0; row < rows; row++) {
  2363.     pP = next_pixrow(ifp, row);
  2364.     if (floyd)
  2365.       begin_floyd_row(fi, pP);
  2366.  
  2367.     for (col = 0; col < cols; col++, pP++) {
  2368.       int ind;
  2369.  
  2370.       if (floyd)
  2371.     pP = next_floyd_pixel(fi);
  2372.  
  2373.       /* Check hash table to see if we have already matched this color. */
  2374.       ind = ppm_lookupcolor(cht, pP);
  2375.       if (ind == -1) {
  2376.     ind = closest_color(chv, colors, maxval, pP);        /* No; search colormap for closest match. */
  2377.     if (usehash) {
  2378.       if (ppm_addtocolorhash(cht, pP, ind) < 0) {
  2379.         pm_message("out of memory adding to hash table, proceeding without it");
  2380.         usehash = 0;
  2381.       }
  2382.     }
  2383.       }
  2384.       if (floyd) {
  2385.     raw_rowbuf[fi->col] = ind;
  2386.     update_floyd_pixel(fi, (int)PPM_GETR(chv[ind].color), (int)PPM_GETG(chv[ind].color), (int)PPM_GETB(chv[ind].color));
  2387.       }
  2388.       else
  2389.     raw_rowbuf[col] = ind;
  2390.     }
  2391.     if (floyd)
  2392.       end_floyd_row(fi);
  2393.     bodysize += encode_row(ofp, raw_rowbuf, cols, nPlanes);
  2394.   }
  2395.   /* clean up */
  2396.   free(raw_rowbuf);
  2397.   ppm_freecolorhash(cht);
  2398.   if (floyd)
  2399.     free_floyd(fi);
  2400.  
  2401.   return bodysize;
  2402. }
  2403.  
  2404. /************ multipalette ************/
  2405.  
  2406. #ifdef ILBM_PCHG
  2407. static pixel *ppmslice[2];                    /* need 2 for laced ILBMs, else 1 */
  2408.  
  2409. void ppm_to_pchg()
  2410. {
  2411. /*
  2412.  * read first slice
  2413.  * build a colormap from this slice
  2414.  * select upto <maxcolors> colors
  2415.  * build colormap from selected colors
  2416.  * map slice to colormap
  2417.  * write slice
  2418.  * while( !finished ) {
  2419.  * read next slice
  2420.  * compute distances for each pixel and select upto
  2421.  * <maxchangesperslice> unused colors in this slice
  2422.  * modify selected colors to the ones with maximum(?) distance
  2423.  * map slice to colormap
  2424.  * write slice
  2425.  * }
  2426.  * 
  2427.  * 
  2428.  * for HAM use a different mapping:
  2429.  * compute distance to closest color in colormap
  2430.  * if( there is no matching color in colormap ) {
  2431.  * compute distances for the three "modify" cases
  2432.  * use the shortest distance from the four cases
  2433.  * }
  2434.  */
  2435. }
  2436.  
  2437. #endif
  2438.  
  2439. /************ ILBM functions ************/
  2440.  
  2441. static void write_std_cmap(chv, colors, maxval)
  2442.     colorhist_vector chv;
  2443.     int colors, maxval;
  2444. {
  2445.   int cmapsize, i;
  2446.  
  2447.   cmapsize = 3 * colors;
  2448.  
  2449.   /* write colormap */
  2450.   put_fourchars("CMAP");
  2451.   put_big_long(cmapsize);
  2452.   if (maxval != MAXCOLVAL) {
  2453.     pixval *table;
  2454.  
  2455.     pm_message("maxval is not %d - automatically rescaling colors", MAXCOLVAL);
  2456.     table = make_val_table(maxval, MAXCOLVAL);
  2457.     for (i = 0; i < colors; i++) {
  2458.       put_byte(table[PPM_GETR(chv[i].color)]);
  2459.       put_byte(table[PPM_GETG(chv[i].color)]);
  2460.       put_byte(table[PPM_GETB(chv[i].color)]);
  2461.     }
  2462.     free(table);
  2463.   }
  2464.   else {
  2465.     for (i = 0; i < colors; i++) {
  2466.       put_byte(PPM_GETR(chv[i].color));
  2467.       put_byte(PPM_GETG(chv[i].color));
  2468.       put_byte(PPM_GETB(chv[i].color));
  2469.     }
  2470.   }
  2471.   if (odd(cmapsize))
  2472.     put_byte(0);
  2473. }
  2474.  
  2475. static void write_form_ilbm(size)
  2476.     int size;
  2477. {
  2478.   put_fourchars("FORM");
  2479.   put_big_long(size);
  2480.   put_fourchars("ILBM");
  2481. }
  2482.  
  2483. static void write_bmhd(cols, rows, nPlanes)
  2484.     int cols, rows, nPlanes;
  2485. {
  2486.   unsigned int xasp = 10, yasp = 10;
  2487.  
  2488.   if (viewportmodes & vmLACE)
  2489.     xasp *= 2;
  2490.   if (viewportmodes & vmHIRES)
  2491.     yasp *= 2;
  2492.  
  2493.   put_fourchars("BMHD");
  2494.   put_big_long(BitMapHeaderSize);
  2495.  
  2496.   put_big_short(cols);
  2497.   put_big_short(rows);
  2498.   put_big_short(0);                        /* x-offset */
  2499.   put_big_short(0);                        /* y-offset */
  2500.   put_byte(nPlanes);                        /* no of planes */
  2501.   put_byte(mskNone);                        /* masking type */
  2502.   put_byte((unsigned char)compr_type);                /* compression type */
  2503.   put_byte(0);                            /* pad1 */
  2504.   put_big_short(0);                        /* tranparentColor */
  2505.   put_byte(xasp);                        /* x-aspect */
  2506.   put_byte(yasp);                        /* y-aspect */
  2507.   put_big_short(cols);                        /* pageWidth */
  2508.   put_big_short(rows);                        /* pageHeight */
  2509. }
  2510.  
  2511. /* encode algorithm by Johan Widen (jw@jwdata.se) */
  2512. const unsigned char ppmtoilbm_bitmask[] =
  2513. {1, 2, 4, 8, 16, 32, 64, 128};
  2514.  
  2515. static int encode_row(outfile, rawrow, cols, nPlanes)
  2516.     FILE *outfile;                        /* if non-NULL, write uncompressed row to this file */
  2517.     rawtype *rawrow;
  2518.     int cols, nPlanes;
  2519. {
  2520.   int plane, bytes;
  2521.   long retbytes = 0;
  2522.  
  2523.   bytes = RowBytes(cols);
  2524.  
  2525.   /* Encode and write raw bytes in plane-interleaved form. */
  2526.   for (plane = 0; plane < nPlanes; plane++) {
  2527.     register int col, cbit;
  2528.     register rawtype *rp;
  2529.     register unsigned char *cp;
  2530.     int mask;
  2531.  
  2532.     mask = 1 << plane;
  2533.     cbit = -1;
  2534.     cp = coded_rowbuf - 1;
  2535.     rp = rawrow;
  2536.     for (col = 0; col < cols; col++, cbit--, rp++) {
  2537.       if (cbit < 0) {
  2538.     cbit = 7;
  2539.     *++cp = 0;
  2540.       }
  2541.       if (*rp & mask)
  2542.     *cp |= ppmtoilbm_bitmask[cbit];
  2543.     }
  2544.     if (outfile) {
  2545.       retbytes += bytes;
  2546.       if (fwrite(coded_rowbuf, 1, bytes, stdout) != bytes)
  2547.     pm_error("write error");
  2548.     }
  2549.     else
  2550.       retbytes += compress_row(bytes);
  2551.   }
  2552.   return retbytes;
  2553. }
  2554.  
  2555. static int compress_row(bytes)
  2556.     int bytes;
  2557. {
  2558.   static int count;
  2559.   int newbytes;
  2560.  
  2561.   /* if new compression methods are defined, do a switch here */
  2562.   newbytes = runbyte1(bytes);
  2563.  
  2564.   if (savemem) {
  2565.     ilbm_body[count].row = MALLOC(newbytes, unsigned char);
  2566.  
  2567.     bcopy(compr_rowbuf, ilbm_body[count].row, newbytes);
  2568.   }
  2569.   else {
  2570.     ilbm_body[count].row = compr_rowbuf;
  2571.     compr_rowbuf = MALLOC(WORSTCOMPR(bytes), unsigned char);
  2572.   }
  2573.   ilbm_body[count].len = newbytes;
  2574.   ++count;
  2575.  
  2576.   return newbytes;
  2577. }
  2578.  
  2579. static void
  2580. write_body ARGS((void))
  2581. {
  2582.   bodyrow *p;
  2583.  
  2584.   for (p = ilbm_body; p->row != NULL; p++) {
  2585.     if (fwrite(p->row, 1, p->len, stdout) != p->len)
  2586.       pm_error("write error");
  2587.   }
  2588.   /* pad byte (if neccessary) is written by do_xxx_body() function */
  2589. }
  2590.  
  2591. static void
  2592. write_camg ARGS((void))
  2593. {
  2594.   if (viewportmodes) {
  2595.     put_fourchars("CAMG");
  2596.     put_big_long(CAMGChunkSize);
  2597.     put_big_long(viewportmodes);
  2598.   }
  2599. }
  2600.  
  2601. /************ compression ************/
  2602.  
  2603. /* runbyte1 algorithm by Robert A. Knop (rknop@mop.caltech.edu) */
  2604. static int runbyte1(size)
  2605.     int size;
  2606. {
  2607.   int in, out, count, hold;
  2608.   register unsigned char *inbuf = coded_rowbuf;
  2609.   register unsigned char *outbuf = compr_rowbuf;
  2610.  
  2611.   in = out = 0;
  2612.   while (in < size) {
  2613.     if ((in < size - 1) && (inbuf[in] == inbuf[in + 1])) {    /*Begin replicate run */
  2614.       for (count = 0, hold = in; in < size && inbuf[in] == inbuf[hold] && count < 128; in++, count++);
  2615.       outbuf[out++] = (unsigned char)(char)(-count + 1);
  2616.       outbuf[out++] = inbuf[hold];
  2617.     }
  2618.     else {                            /*Do a literal run */
  2619.       hold = out;
  2620.       out++;
  2621.       count = 0;
  2622.       while (((in >= size - 2) && (in < size)) || ((in < size - 2) && ((inbuf[in] != inbuf[in + 1]) || (inbuf[in] != inbuf[in + 2])))) {
  2623.     outbuf[out++] = inbuf[in++];
  2624.     if (++count >= 128)
  2625.       break;
  2626.       }
  2627.       outbuf[hold] = count - 1;
  2628.     }
  2629.   }
  2630.   return (out);
  2631. }
  2632.  
  2633. /************ PPM functions ************/
  2634.  
  2635. static int closest_color(chv, colors, cmaxval, pP)
  2636.     colorhist_vector chv;
  2637.     int colors;
  2638.     pixval cmaxval;
  2639.     pixel *pP;
  2640. {
  2641.   /* Search colormap for closest match.       */
  2642.   /* algorithm taken from ppmquant.c   -IUW   */
  2643.   register int i, r1, g1, b1;
  2644.   int ind;
  2645.   long dist;
  2646.  
  2647.   r1 = PPM_GETR(*pP);
  2648.   g1 = PPM_GETG(*pP);
  2649.   b1 = PPM_GETB(*pP);
  2650.   dist = 2000000000;
  2651.   for (i = 0; i < colors; i++) {
  2652.     register int r2, g2, b2;
  2653.     long newdist;
  2654.  
  2655.     r2 = PPM_GETR(chv[i].color);
  2656.     g2 = PPM_GETG(chv[i].color);
  2657.     b2 = PPM_GETB(chv[i].color);
  2658.     newdist = (r1 - r2) * (r1 - r2) +
  2659.       (g1 - g2) * (g1 - g2) +
  2660.       (b1 - b2) * (b1 - b2);
  2661.  
  2662.     if (newdist < dist) {
  2663.       ind = i;
  2664.       dist = newdist;
  2665.     }
  2666.   }
  2667.   return ind;
  2668. }
  2669.  
  2670. /************ floyd-steinberg error diffusion ************/
  2671.  
  2672. static floydinfo *
  2673.   init_floyd(cols, maxval, alternate)
  2674.     int cols;
  2675.     pixval maxval;
  2676.     int alternate;
  2677. {
  2678.   register int i;
  2679.   floydinfo *fi;
  2680.  
  2681.   fi = MALLOC(1, floydinfo);
  2682.  
  2683.   fi->thisrederr = MALLOC(cols + 2, long);
  2684.   fi->thisgreenerr = MALLOC(cols + 2, long);
  2685.   fi->thisblueerr = MALLOC(cols + 2, long);
  2686.   fi->nextrederr = MALLOC(cols + 2, long);
  2687.   fi->nextgreenerr = MALLOC(cols + 2, long);
  2688.   fi->nextblueerr = MALLOC(cols + 2, long);
  2689.  
  2690.   fi->lefttoright = 1;
  2691.   fi->cols = cols;
  2692.   fi->maxval = maxval;
  2693.   fi->alternate = alternate;
  2694.  
  2695.   for (i = 0; i < cols + 2; i++)
  2696.     fi->thisrederr[i] = fi->thisgreenerr[i] = fi->thisblueerr[i] = 0;
  2697.  
  2698.   return fi;
  2699. }
  2700.  
  2701. static void free_floyd(fi)
  2702.     floydinfo *fi;
  2703. {
  2704.   free(fi->thisrederr);
  2705.   free(fi->thisgreenerr);
  2706.   free(fi->thisblueerr);
  2707.   free(fi->nextrederr);
  2708.   free(fi->nextgreenerr);
  2709.   free(fi->nextblueerr);
  2710.   free(fi);
  2711. }
  2712.  
  2713. static void begin_floyd_row(fi, prow)
  2714.     floydinfo *fi;
  2715.     pixel *prow;
  2716. {
  2717.   register int i;
  2718.  
  2719.   fi->pixrow = prow;
  2720.  
  2721.   for (i = 0; i < fi->cols + 2; i++)
  2722.     fi->nextrederr[i] = fi->nextgreenerr[i] = fi->nextblueerr[i] = 0;
  2723.  
  2724.   if (fi->lefttoright) {
  2725.     fi->col = 0;
  2726.     fi->col_end = fi->cols;
  2727.   }
  2728.   else {
  2729.     fi->col = fi->cols - 1;
  2730.     fi->col_end = -1;
  2731.   }
  2732. }
  2733.  
  2734. #define FS_GREEN_WEIGHT     1
  2735. #define FS_RED_WEIGHT       2                    /* luminance of component relative to green */
  2736. #define FS_BLUE_WEIGHT      5
  2737.  
  2738. static pixel *
  2739.   next_floyd_pixel(fi)
  2740.     floydinfo *fi;
  2741. {
  2742.   register long r, g, b;
  2743.   register pixel *pP;
  2744.   int errcol = fi->col + 1;
  2745.   pixval maxval = fi->maxval;
  2746.  
  2747. #ifdef DEBUG
  2748.   if (fi->col == fi->col_end)
  2749.     pm_error("fs - access out of array bounds");        /* should never happen */
  2750. #endif
  2751.  
  2752.   pP = &(fi->pixrow[fi->col]);
  2753.  
  2754.   /* Use Floyd-Steinberg errors to adjust actual color. */
  2755.   r = fi->thisrederr[errcol];
  2756.   if (r < 0)
  2757.     r -= 8;
  2758.   else
  2759.     r += 8;
  2760.   r /= 16;
  2761.   g = fi->thisgreenerr[errcol];
  2762.   if (g < 0)
  2763.     g -= 8;
  2764.   else
  2765.     g += 8;
  2766.   g /= 16;
  2767.   b = fi->thisblueerr[errcol];
  2768.   if (b < 0)
  2769.     b -= 8;
  2770.   else
  2771.     b += 8;
  2772.   b /= 16;
  2773.  
  2774.   if (floyd == 2) {                        /* EXPERIMENTAL */
  2775.     r /= FS_RED_WEIGHT;
  2776.     b /= FS_BLUE_WEIGHT;
  2777.   }
  2778.  
  2779.   r += PPM_GETR(*pP);
  2780.   if (r < 0)
  2781.     r = 0;
  2782.   else if (r > maxval)
  2783.     r = maxval;
  2784.   g += PPM_GETG(*pP);
  2785.   if (g < 0)
  2786.     g = 0;
  2787.   else if (g > maxval)
  2788.     g = maxval;
  2789.   b += PPM_GETB(*pP);
  2790.   if (b < 0)
  2791.     b = 0;
  2792.   else if (b > maxval)
  2793.     b = maxval;
  2794.  
  2795.   PPM_ASSIGN(*pP, r, g, b);
  2796.  
  2797.   fi->red = r;
  2798.   fi->green = g;
  2799.   fi->blue = b;
  2800.  
  2801.   return pP;
  2802. }
  2803.  
  2804. static void update_floyd_pixel(fi, r, g, b)
  2805.     floydinfo *fi;
  2806.     int r, g, b;
  2807. {
  2808.   register long rerr, gerr, berr, err;
  2809.   int col = fi->col;
  2810.   int errcol = col + 1;
  2811.   long two_err;
  2812.  
  2813.   rerr = (long)(fi->red) - r;
  2814.   gerr = (long)(fi->green) - g;
  2815.   berr = (long)(fi->blue) - b;
  2816.  
  2817.   if (fi->lefttoright) {
  2818.     two_err = 2 * rerr;
  2819.     err = rerr;
  2820.     fi->nextrederr[errcol + 1] += err;                /* 1/16 */
  2821.     err += two_err;
  2822.     fi->nextrederr[errcol - 1] += err;                /* 3/16 */
  2823.     err += two_err;
  2824.     fi->nextrederr[errcol] += err;                /* 5/16 */
  2825.     err += two_err;
  2826.     fi->thisrederr[errcol + 1] += err;                /* 7/16 */
  2827.  
  2828.     two_err = 2 * gerr;
  2829.     err = gerr;
  2830.     fi->nextgreenerr[errcol + 1] += err;            /* 1/16 */
  2831.     err += two_err;
  2832.     fi->nextgreenerr[errcol - 1] += err;            /* 3/16 */
  2833.     err += two_err;
  2834.     fi->nextgreenerr[errcol] += err;                /* 5/16 */
  2835.     err += two_err;
  2836.     fi->thisgreenerr[errcol + 1] += err;            /* 7/16 */
  2837.  
  2838.     two_err = 2 * berr;
  2839.     err = berr;
  2840.     fi->nextblueerr[errcol + 1] += err;                /* 1/16 */
  2841.     err += two_err;
  2842.     fi->nextblueerr[errcol - 1] += err;                /* 3/16 */
  2843.     err += two_err;
  2844.     fi->nextblueerr[errcol] += err;                /* 5/16 */
  2845.     err += two_err;
  2846.     fi->thisblueerr[errcol + 1] += err;                /* 7/16 */
  2847.  
  2848.     fi->col++;
  2849.   }
  2850.   else {
  2851.     two_err = 2 * rerr;
  2852.     err = rerr;
  2853.     fi->nextrederr[errcol - 1] += err;                /* 1/16 */
  2854.     err += two_err;
  2855.     fi->nextrederr[errcol + 1] += err;                /* 3/16 */
  2856.     err += two_err;
  2857.     fi->nextrederr[errcol] += err;                /* 5/16 */
  2858.     err += two_err;
  2859.     fi->thisrederr[errcol - 1] += err;                /* 7/16 */
  2860.  
  2861.     two_err = 2 * gerr;
  2862.     err = gerr;
  2863.     fi->nextgreenerr[errcol - 1] += err;            /* 1/16 */
  2864.     err += two_err;
  2865.     fi->nextgreenerr[errcol + 1] += err;            /* 3/16 */
  2866.     err += two_err;
  2867.     fi->nextgreenerr[errcol] += err;                /* 5/16 */
  2868.     err += two_err;
  2869.     fi->thisgreenerr[errcol - 1] += err;            /* 7/16 */
  2870.  
  2871.     two_err = 2 * berr;
  2872.     err = berr;
  2873.     fi->nextblueerr[errcol - 1] += err;                /* 1/16 */
  2874.     err += two_err;
  2875.     fi->nextblueerr[errcol + 1] += err;                /* 3/16 */
  2876.     err += two_err;
  2877.     fi->nextblueerr[errcol] += err;                /* 5/16 */
  2878.     err += two_err;
  2879.     fi->thisblueerr[errcol - 1] += err;                /* 7/16 */
  2880.  
  2881.     fi->col--;
  2882.   }
  2883. }
  2884.  
  2885. static void end_floyd_row(fi)
  2886.     floydinfo *fi;
  2887. {
  2888.   long *tmp;
  2889.  
  2890.   tmp = fi->thisrederr;
  2891.   fi->thisrederr = fi->nextrederr;
  2892.   fi->nextrederr = tmp;
  2893.   tmp = fi->thisgreenerr;
  2894.   fi->thisgreenerr = fi->nextgreenerr;
  2895.   fi->nextgreenerr = tmp;
  2896.   tmp = fi->thisblueerr;
  2897.   fi->thisblueerr = fi->nextblueerr;
  2898.   fi->nextblueerr = tmp;
  2899.   if (fi->alternate)
  2900.     fi->lefttoright = !(fi->lefttoright);
  2901. }
  2902.  
  2903. /************ other utility functions ************/
  2904.  
  2905. static void alloc_body_array(rows, nPlanes)
  2906.     int rows, nPlanes;
  2907. {
  2908.   ilbm_body = MALLOC(rows * nPlanes + 1, bodyrow);
  2909.   ilbm_body[rows * nPlanes].row = NULL;
  2910. }
  2911.  
  2912. static int colorstobpp(colors)
  2913.     int colors;
  2914. {
  2915.   int i;
  2916.  
  2917.   for (i = 1; i <= MAXPLANES; i++) {
  2918.     if (colors <= (1 << i))
  2919.       return i;
  2920.   }
  2921.   pm_error("too many planes (max %d)", MAXPLANES);
  2922.   /*NOTREACHED */
  2923. }
  2924.  
  2925. static void put_big_short(s)
  2926.     short s;
  2927. {
  2928.   if (pm_writebigshort(stdout, s) == -1)
  2929.     pm_error("write error");
  2930. }
  2931.  
  2932. static void put_big_long(l)
  2933.     long l;
  2934. {
  2935.   if (pm_writebiglong(stdout, l) == -1)
  2936.     pm_error("write error");
  2937. }
  2938.  
  2939. static pixval *
  2940.   make_val_table(oldmaxval, newmaxval)
  2941.     pixval oldmaxval, newmaxval;
  2942. {
  2943.   int i;
  2944.   pixval *table;
  2945.  
  2946.   table = MALLOC(oldmaxval + 1, pixval);
  2947.   for (i = 0; i <= oldmaxval; i++)
  2948.     table[i] = (i * newmaxval + oldmaxval / 2) / oldmaxval;
  2949.  
  2950.   return table;
  2951. }
  2952.  
  2953. static void *
  2954.   xmalloc(bytes)
  2955.     int bytes;
  2956. {
  2957.   void *mem;
  2958.  
  2959.   mem = malloc(bytes);
  2960.   if (mem == NULL)
  2961.     pm_error("out of memory allocating %d bytes", bytes);
  2962.   return mem;
  2963. }
  2964.  
  2965. static int gFormat;
  2966. static int gCols;
  2967. static int gMaxval;
  2968.  
  2969. static void init_read(fp, colsP, rowsP, maxvalP, formatP, readall)
  2970.     FILE *fp;
  2971.     int *colsP, *rowsP;
  2972.     pixval *maxvalP;
  2973.     int *formatP;
  2974.     int readall;
  2975. {
  2976.   ppm_readppminit(fp, colsP, rowsP, maxvalP, formatP);
  2977.   if (readall) {
  2978.     int row;
  2979.  
  2980.     pixels = ppm_allocarray(*colsP, *rowsP);
  2981.     for (row = 0; row < *rowsP; row++)
  2982.       ppm_readppmrow(fp, pixels[row], *colsP, *maxvalP, *formatP);
  2983.     /* pixels = ppm_readppm(fp, colsP, rowsP, maxvalP); */
  2984.   }
  2985.   else {
  2986.     pixrow = ppm_allocrow(*colsP);
  2987.   }
  2988.   gCols = *colsP;
  2989.   gMaxval = *maxvalP;
  2990.   gFormat = *formatP;
  2991. }
  2992.  
  2993. static pixel *
  2994.   next_pixrow(fp, row)
  2995.     FILE *fp;
  2996.     int row;
  2997. {
  2998.   if (pixels)
  2999.     pixrow = pixels[row];
  3000.   else {
  3001. #ifdef DEBUG
  3002.     static int rowcnt;
  3003.  
  3004.     if (row != rowcnt)
  3005.       pm_error("big mistake");
  3006.     rowcnt++;
  3007. #endif
  3008.     ppm_readppmrow(fp, pixrow, gCols, gMaxval, gFormat);
  3009.   }
  3010.   return pixrow;
  3011. }
  3012.